diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
index c6f3a248a82a3..a9d8dfec98620 100644
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -8,6 +8,7 @@
#include "MobileViewportManager.h"
#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/LayerTransactionChild.h"
#include "nsPresContext.h"
#include "nsCaret.h"
#include "nsContentList.h"
diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp
index 86a5cc876c1c7..af5d09df135b3 100644
--- a/dom/canvas/ClientWebGLContext.cpp
+++ b/dom/canvas/ClientWebGLContext.cpp
@@ -20,6 +20,7 @@
#include "mozilla/ipc/Shmem.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/OOPCanvasRenderer.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/layers/WebRenderUserData.h"
diff --git a/dom/canvas/HostWebGLContext.cpp b/dom/canvas/HostWebGLContext.cpp
index 9d0b47d9a03e8..e009f1942600d 100644
--- a/dom/canvas/HostWebGLContext.cpp
+++ b/dom/canvas/HostWebGLContext.cpp
@@ -6,6 +6,7 @@
#include "HostWebGLContext.h"
#include "CompositableHost.h"
+#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "MozFramebuffer.h"
diff --git a/dom/canvas/PWebGL.ipdl b/dom/canvas/PWebGL.ipdl
index 5403b8c82d413..44086b1746116 100644
--- a/dom/canvas/PWebGL.ipdl
+++ b/dom/canvas/PWebGL.ipdl
@@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PCompositorBridge;
+include protocol PLayerTransaction;
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using mozilla::layers::SurfaceDescriptor from "mozilla/layers/LayersTypes.h";
diff --git a/dom/canvas/WebGLParent.cpp b/dom/canvas/WebGLParent.cpp
index d72422b79f024..7042027d9078a 100644
--- a/dom/canvas/WebGLParent.cpp
+++ b/dom/canvas/WebGLParent.cpp
@@ -6,6 +6,7 @@
#include "WebGLParent.h"
#include "WebGLChild.h"
+#include "mozilla/layers/LayerTransactionParent.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "ImageContainer.h"
#include "HostWebGLContext.h"
diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp
index 44e24f3937708..5ef18e7479c1f 100644
--- a/dom/ipc/BrowserChild.cpp
+++ b/dom/ipc/BrowserChild.cpp
@@ -92,6 +92,7 @@
#include "mozilla/layers/IAPZCTreeManager.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/InputAPZContext.h"
+#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "nsBrowserStatusFilter.h"
#include "nsColorPickerProxy.h"
diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h
index e882460612a09..b20770774d16b 100644
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -158,6 +158,7 @@ enum class CompositableType : uint8_t {
UNKNOWN,
CONTENT_TILED, // tiled painted layer
IMAGE, // image with single buffering
+ IMAGE_BRIDGE, // ImageBridge protocol
CONTENT_SINGLE, // painted layer interface, single buffering
CONTENT_DOUBLE, // painted layer interface, double buffering
COUNT
diff --git a/gfx/layers/LayerManager.h b/gfx/layers/LayerManager.h
index 97b82b6c549ed..0c7e4d8bad5aa 100644
--- a/gfx/layers/LayerManager.h
+++ b/gfx/layers/LayerManager.h
@@ -72,6 +72,8 @@ class RefLayer;
class HostLayer;
class FocusTarget;
class KnowsCompositor;
+class ShadowableLayer;
+class ShadowLayerForwarder;
class LayerManagerComposite;
class TransactionIdAllocator;
class FrameUniformityData;
diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp
index edce6fc97ee94..1451769a8fb49 100644
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -46,6 +46,7 @@
#include "mozilla/layers/LayerManagerComposite.h" // for HostLayer
#include "mozilla/layers/LayersMessages.h" // for SpecificLayerAttributes, CompositorAnimations (ptr only), ContainerLayerAt...
#include "mozilla/layers/LayersTypes.h" // for EventRegions, operator<<, CompositionPayload, CSSTransformMatrix, MOZ_LAYE...
+#include "mozilla/layers/ShadowLayers.h" // for ShadowableLayer
#include "nsBaseHashtable.h" // for nsBaseHashtable<>::Iterator, nsBaseHashtable<>::LookupResult
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
#include "nsPrintfCString.h" // for nsPrintfCString
@@ -1157,6 +1158,8 @@ void Layer::Dump(std::stringstream& aStream, const char* aPrefix,
bool dumpCompositorTexture = gfxEnv::DumpCompositorTextures() &&
AsHostLayer() &&
AsHostLayer()->GetCompositableHost();
+ bool dumpClientTexture = gfxEnv::DumpPaint() && AsShadowableLayer() &&
+ AsShadowableLayer()->GetCompositableClient();
nsCString layerId(Name());
layerId.Append('-');
layerId.AppendInt((uint64_t)this);
@@ -1164,7 +1167,7 @@ void Layer::Dump(std::stringstream& aStream, const char* aPrefix,
if (aDumpHtml) {
aStream << nsPrintfCString(R"(
GetCompositableHost()->Dump(aStream, aPrefix, aDumpHtml);
+ } else if (dumpClientTexture) {
+ if (aDumpHtml) {
+ aStream << nsPrintfCString(R"()";
+ }
}
#endif
if (aDumpHtml) {
aStream << "";
+#ifdef MOZ_DUMP_PAINTING
+ if (dumpClientTexture) {
+ aStream << nsPrintfCString("
\n",
+ layerId.BeginReading())
+ .get();
+ }
+#endif
}
if (Layer* mask = GetMaskLayer()) {
diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h
index 6b7495f1b0cba..8440406df30b5 100644
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -74,6 +74,7 @@ class CompositorAnimations;
class CanvasLayer;
class RefLayer;
class HostLayer;
+class ShadowableLayer;
class SpecificLayerAttributes;
class Compositor;
class TransformData;
@@ -917,6 +918,12 @@ class Layer {
*/
virtual HostLayer* AsHostLayer() { return nullptr; }
+ /**
+ * Dynamic cast to a ShadowableLayer. Return null if this is not a
+ * ShadowableLayer. Can be used anytime.
+ */
+ virtual ShadowableLayer* AsShadowableLayer() { return nullptr; }
+
// These getters can be used anytime. They return the effective
// values that should be used when drawing this layer to screen,
// accounting for this layer possibly being a shadow.
diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h
index f6523e33212f2..c9a63fcc5ced3 100644
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -23,7 +23,12 @@
#endif
#define MOZ_LAYERS_LOG(_args) \
MOZ_LOG(LayerManager::GetLog(), LogLevel::Debug, _args)
-#define MOZ_LAYERS_LOG_IF_SHADOWABLE(layer, _args)
+#define MOZ_LAYERS_LOG_IF_SHADOWABLE(layer, _args) \
+ do { \
+ if (layer->AsShadowableLayer()) { \
+ MOZ_LOG(LayerManager::GetLog(), LogLevel::Debug, _args); \
+ } \
+ } while (0)
#define INVALID_OVERLAY -1
diff --git a/gfx/layers/PersistentBufferProvider.cpp b/gfx/layers/PersistentBufferProvider.cpp
index e214489351f79..0c64c6a756083 100644
--- a/gfx/layers/PersistentBufferProvider.cpp
+++ b/gfx/layers/PersistentBufferProvider.cpp
@@ -7,8 +7,8 @@
#include "PersistentBufferProvider.h"
#include "Layers.h"
+#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/layers/TextureClient.h"
-#include "mozilla/layers/TextureForwarder.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/Maybe.h"
diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp
index 08f92df085dd0..f5e7b160b3cdd 100644
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -69,6 +69,7 @@
#include "mozilla/layers/APZUtils.h" // for AsyncTransform
#include "mozilla/layers/CompositorController.h" // for CompositorController
#include "mozilla/layers/DirectionUtils.h" // for GetAxis{Start,End,Length,Scale}
+#include "mozilla/layers/LayerTransactionParent.h" // for LayerTransactionParent
#include "mozilla/layers/MetricsSharingController.h" // for MetricsSharingController
#include "mozilla/mozalloc.h" // for operator new, etc
#include "mozilla/Unused.h" // for unused
@@ -3659,6 +3660,7 @@ Maybe AsyncPanZoomController::GetCurrentAnimationDestination(
ParentLayerPoint
AsyncPanZoomController::AdjustHandoffVelocityForOverscrollBehavior(
ParentLayerPoint& aHandoffVelocity) const {
+
ParentLayerPoint residualVelocity;
ScrollDirections handoffDirections = GetAllowedHandoffDirections();
if (!handoffDirections.contains(ScrollDirection::eHorizontal)) {
diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp
index 89b4df6da41ce..1230840e3e510 100644
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -14,6 +14,7 @@
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/RepaintRequest.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp
index 9f4216b4a2d2a..d5ad5c26e48d8 100644
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -23,8 +23,8 @@
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc
#include "mozilla/layers/ISurfaceAllocator.h"
-#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
-#include "mozilla/layers/TextureForwarder.h"
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
#include "mozilla/layers/TextureClientOGL.h" // for SurfaceTextureClient
#include "mozilla/mozalloc.h" // for operator delete, etc
@@ -48,6 +48,9 @@ already_AddRefed ImageClient::CreateImageClient(
result =
new ImageClientSingle(aForwarder, aFlags, CompositableType::IMAGE);
break;
+ case CompositableType::IMAGE_BRIDGE:
+ result = new ImageClientBridge(aForwarder, aFlags);
+ break;
case CompositableType::UNKNOWN:
result = nullptr;
break;
@@ -274,5 +277,29 @@ ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
mType(aType),
mLastUpdateGenerationCounter(0) {}
+ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
+ TextureFlags aFlags)
+ : ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE) {}
+
+bool ImageClientBridge::UpdateImage(ImageContainer* aContainer,
+ uint32_t aContentFlags) {
+ if (!GetForwarder() || !mLayer) {
+ return false;
+ }
+ if (mAsyncContainerHandle == aContainer->GetAsyncContainerHandle()) {
+ return true;
+ }
+
+ mAsyncContainerHandle = aContainer->GetAsyncContainerHandle();
+ if (!mAsyncContainerHandle) {
+ // If we couldn't contact a working ImageBridgeParent, just return.
+ return true;
+ }
+
+ static_cast(GetForwarder())
+ ->AttachAsyncCompositable(mAsyncContainerHandle, mLayer);
+ return true;
+}
+
} // namespace layers
} // namespace mozilla
diff --git a/gfx/layers/client/ImageClient.h b/gfx/layers/client/ImageClient.h
index 77f3e57c5d9d8..19b169c132968 100644
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -118,6 +118,24 @@ class ImageClientSingle : public ImageClient {
nsTArray mBuffers;
};
+/**
+ * Image class to be used for async image uploads using the image bridge
+ * protocol.
+ * We store the ImageBridge id in the TextureClientIdentifier.
+ */
+class ImageClientBridge : public ImageClient {
+ public:
+ ImageClientBridge(CompositableForwarder* aFwd, TextureFlags aFlags);
+
+ bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) override;
+ bool Connect(ImageContainer* aImageContainer) override { return false; }
+
+ TextureInfo GetTextureInfo() const override { return TextureInfo(mType); }
+
+ protected:
+ CompositableHandle mAsyncContainerHandle;
+};
+
} // namespace layers
} // namespace mozilla
diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp
index f1cff13f4b913..fe7c75ebebc89 100644
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -33,6 +33,7 @@
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/PTextureChild.h"
+#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/layers/TextureClientOGL.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "mozilla/layers/TextureRecorded.h"
@@ -1033,6 +1034,13 @@ bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
+ if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
+ // Do the DOM labeling.
+ if (nsISerialEventTarget* target = forwarder->GetEventTarget()) {
+ forwarder->GetCompositorBridgeChild()->ReplaceEventTargetForActor(
+ mActor, target);
+ }
+ }
mActor->mCompositableForwarder = aForwarder;
mActor->mUsesImageBridge =
aForwarder->GetTextureForwarder()->UsesImageBridge();
@@ -1051,6 +1059,12 @@ bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) {
mExternalImageId =
aForwarder->GetTextureForwarder()->GetNextExternalImageId();
+ nsISerialEventTarget* target = nullptr;
+ // Get the layers id if the forwarder is a ShadowLayerForwarder.
+ if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
+ target = forwarder->GetEventTarget();
+ }
+
ReadLockDescriptor readLockDescriptor = null_t();
if (mReadLock) {
mReadLock->Serialize(readLockDescriptor, GetAllocator()->GetParentPid());
@@ -1058,7 +1072,7 @@ bool TextureClient::InitIPDLActor(CompositableForwarder* aForwarder) {
PTextureChild* actor = aForwarder->GetTextureForwarder()->CreateTexture(
desc, readLockDescriptor, aForwarder->GetCompositorBackendType(),
- GetFlags(), mSerial, mExternalImageId, nullptr);
+ GetFlags(), mSerial, mExternalImageId, target);
if (!actor) {
gfxCriticalNote << static_cast(desc.type()) << ", "
diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp
index d229ca791869c..056f26de04a21 100644
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -110,6 +110,9 @@ already_AddRefed CompositableHost::Create(
const TextureInfo& aTextureInfo, bool aUseWebRender) {
RefPtr result;
switch (aTextureInfo.mCompositableType) {
+ case CompositableType::IMAGE_BRIDGE:
+ NS_ERROR("Cannot create an image bridge compositable this way");
+ break;
case CompositableType::CONTENT_TILED:
result = new TiledContentHost(aTextureInfo);
break;
diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h
index 45c8bdac2c6f8..412af3e859e63 100644
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -22,6 +22,7 @@ class CompositableClient;
class CompositableHandle;
class ImageContainer;
class PTextureChild;
+class ShadowLayerForwarder;
class SurfaceDescriptorTiles;
class TextureClient;
class ThebesBufferData;
@@ -111,6 +112,8 @@ class CompositableForwarder : public KnowsCompositor {
static uint32_t GetMaxFileDescriptorsPerMessage();
+ virtual ShadowLayerForwarder* AsLayerForwarder() { return nullptr; }
+
protected:
nsTArray> mTexturesToRemove;
nsTArray> mCompositableClientsToRemove;
diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp
index a809069f1c5e0..ed2d28a1c311a 100644
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -17,6 +17,8 @@
#include "mozilla/layers/APZCTreeManagerChild.h"
#include "mozilla/layers/CanvasChild.h"
#include "mozilla/layers/LayerManager.h"
+#include "mozilla/layers/LayerTransactionChild.h"
+#include "mozilla/layers/PLayerTransactionChild.h"
#include "mozilla/layers/PTextureChild.h"
#include "mozilla/layers/TextureClient.h" // for TextureClient
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
@@ -55,6 +57,7 @@
using mozilla::Unused;
using mozilla::gfx::GPUProcessManager;
+using mozilla::layers::LayerTransactionChild;
namespace mozilla {
namespace layers {
@@ -170,6 +173,14 @@ void CompositorBridgeChild::Destroy() {
return;
}
+ AutoTArray transactions;
+ ManagedPLayerTransactionChild(transactions);
+ for (int i = transactions.Length() - 1; i >= 0; --i) {
+ RefPtr layers =
+ static_cast(transactions[i]);
+ layers->Destroy();
+ }
+
AutoTArray wrBridges;
ManagedPWebRenderBridgeChild(wrBridges);
for (int i = wrBridges.Length() - 1; i >= 0; --i) {
@@ -303,6 +314,22 @@ bool CompositorBridgeChild::CompositorIsInGPUProcess() {
return bridge->OtherPid() != dom::ContentChild::GetSingleton()->OtherPid();
}
+PLayerTransactionChild* CompositorBridgeChild::AllocPLayerTransactionChild(
+ const nsTArray& aBackendHints, const LayersId& aId) {
+ LayerTransactionChild* c = new LayerTransactionChild(aId);
+ c->AddIPDLReference();
+
+ return c;
+}
+
+bool CompositorBridgeChild::DeallocPLayerTransactionChild(
+ PLayerTransactionChild* actor) {
+ LayersId childId = static_cast(actor)->GetId();
+ ClearSharedFrameMetricsData(childId);
+ static_cast(actor)->ReleaseIPDLReference();
+ return true;
+}
+
mozilla::ipc::IPCResult CompositorBridgeChild::RecvInvalidateLayers(
const LayersId& aLayersId) {
if (mLayerManager) {
diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h
index abf0476c0dd62..45c6b9beb8087 100644
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -241,6 +241,11 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
void PrepareFinalDestroy();
void AfterDestroy();
+ PLayerTransactionChild* AllocPLayerTransactionChild(
+ const nsTArray& aBackendHints, const LayersId& aId);
+
+ bool DeallocPLayerTransactionChild(PLayerTransactionChild* aChild);
+
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult RecvSharedCompositorFrameMetrics(
diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp
index e901099c76365..14889396fa7d0 100644
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -12,6 +12,7 @@
#include // for pair
#include "apz/src/APZCTreeManager.h" // for APZCTreeManager
+#include "LayerTransactionParent.h" // for LayerTransactionParent
#include "RenderTrace.h" // for RenderTraceLayers
#include "base/process.h" // for ProcessId
#include "gfxContext.h" // for gfxContext
@@ -56,6 +57,7 @@
#include "mozilla/layers/LayerTreeOwnerTracker.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/OMTASampler.h"
+#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/RemoteContentController.h"
#include "mozilla/layers/UiCompositorControllerParent.h"
#include "mozilla/layers/WebRenderBridgeParent.h"
@@ -222,7 +224,8 @@ CompositorBridgeParent::LayerTreeState::LayerTreeState()
: mApzcTreeManagerParent(nullptr),
mParent(nullptr),
mLayerManager(nullptr),
- mContentCompositorBridgeParent(nullptr) {}
+ mContentCompositorBridgeParent(nullptr),
+ mLayerTree(nullptr) {}
CompositorBridgeParent::LayerTreeState::~LayerTreeState() {
if (mController) {
@@ -773,6 +776,27 @@ void CompositorBridgeParent::ResumeCompositionAndResize(int x, int y, int width,
ResumeComposition();
}
+void CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree,
+ const TimeDuration& aPaintTime) {
+ // We get a lot of paint timings for things with empty transactions.
+ if (!mLayerManager || aPaintTime.ToMilliseconds() < 1.0) {
+ return;
+ }
+
+ mLayerManager->SetPaintTime(aPaintTime);
+}
+
+void CompositorBridgeParent::RegisterPayloads(
+ LayerTransactionParent* aLayerTree,
+ const nsTArray& aPayload) {
+ // We get a lot of paint timings for things with empty transactions.
+ if (!mLayerManager) {
+ return;
+ }
+
+ mLayerManager->RegisterPayloads(aPayload);
+}
+
void CompositorBridgeParent::NotifyShadowTreeTransaction(
LayersId aId, bool aIsFirstPaint, const FocusTarget& aFocusTarget,
bool aScheduleComposite, uint32_t aPaintSequenceNumber,
@@ -839,6 +863,107 @@ void CompositorBridgeParent::SetShadowProperties(Layer* aLayer) {
});
}
+void CompositorBridgeParent::CompositeToTarget(VsyncId aId, DrawTarget* aTarget,
+ const gfx::IntRect* aRect) {
+ AUTO_PROFILER_TRACING_MARKER("Paint", "Composite", GRAPHICS);
+ AUTO_PROFILER_LABEL("CompositorBridgeParent::CompositeToTarget", GRAPHICS);
+ PerfStats::AutoMetricRecording autoRecording;
+
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
+ "Composite can only be called on the compositor thread");
+ TimeStamp start = TimeStamp::Now();
+
+ if (!CanComposite()) {
+ TimeStamp end = TimeStamp::Now();
+ DidComposite(aId, start, end);
+ return;
+ }
+
+ AutoResolveRefLayers resolve(mCompositionManager, this);
+
+ nsCString none;
+ if (aTarget) {
+ mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect);
+ } else {
+ mLayerManager->BeginTransaction(none);
+ }
+
+ SetShadowProperties(mLayerManager->GetRoot());
+
+ if (mForceCompositionTask && !mOverrideComposeReadiness) {
+ if (mCompositionManager->ReadyForCompose()) {
+ mForceCompositionTask->Cancel();
+ mForceCompositionTask = nullptr;
+ } else {
+ return;
+ }
+ }
+
+ mCompositionManager->ComputeRotation();
+
+ SampleTime time = mTestTime ? SampleTime::FromTest(*mTestTime)
+ : mCompositorScheduler->GetLastComposeTime();
+ bool requestNextFrame =
+ mCompositionManager->TransformShadowTree(time, mVsyncRate);
+
+ if (requestNextFrame) {
+ ScheduleComposition();
+ }
+
+ RenderTraceLayers(mLayerManager->GetRoot(), "0000");
+
+ if (StaticPrefs::layers_dump_host_layers() || StaticPrefs::layers_dump()) {
+ printf_stderr("Painting --- compositing layer tree:\n");
+ mLayerManager->Dump(/* aSorted = */ true);
+ }
+ mLayerManager->SetDebugOverlayWantsNextFrame(false);
+ mLayerManager->EndTransaction(time.Time());
+
+ if (!aTarget) {
+ TimeStamp end = TimeStamp::Now();
+ DidComposite(aId, start, end);
+ }
+
+ // We're not really taking advantage of the stored composite-again-time here.
+ // We might be able to skip the next few composites altogether. However,
+ // that's a bit complex to implement and we'll get most of the advantage
+ // by skipping compositing when we detect there's nothing invalid. This is why
+ // we do "composite until" rather than "composite again at".
+ //
+ // TODO(bug 1328602) Figure out what we should do here with the render thread.
+ if (!mLayerManager->GetCompositeUntilTime().IsNull() ||
+ mLayerManager->DebugOverlayWantsNextFrame()) {
+ ScheduleComposition();
+ }
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ TimeDuration executionTime =
+ TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime().Time();
+ TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
+ int32_t frameRate = CalculateCompositionFrameRate();
+ if (frameRate > 0) {
+ frameBudget = TimeDuration::FromSeconds(1.0 / frameRate);
+ }
+ if (executionTime > frameBudget) {
+ printf_stderr("Compositor: Composite execution took %4.1f ms\n",
+ executionTime.ToMilliseconds());
+ }
+#endif
+
+ // 0 -> Full-tilt composite
+ if (StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 ||
+ mLayerManager->AlwaysScheduleComposite()) {
+ // Special full-tilt composite mode for performance testing
+ ScheduleComposition();
+ }
+
+ // TODO(bug 1328602) Need an equivalent that works with the rende thread.
+ mLayerManager->SetCompositionTime(TimeStamp());
+
+ mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
+ start);
+}
+
void CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget,
const gfx::IntRect* aRect) {
AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS);
@@ -991,6 +1116,68 @@ void CompositorBridgeParent::ScheduleRotationOnCompositorThread(
}
}
+void CompositorBridgeParent::ShadowLayersUpdated(
+ LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo,
+ bool aHitTestUpdate) {
+ const TargetConfig& targetConfig = aInfo.targetConfig();
+
+ ScheduleRotationOnCompositorThread(targetConfig, aInfo.isFirstPaint());
+
+ // Instruct the LayerManager to update its render bounds now. Since all the
+ // orientation change, dimension change would be done at the stage, update the
+ // size here is free of race condition.
+ mLayerManager->UpdateRenderBounds(targetConfig.naturalBounds());
+ mLayerManager->SetRegionToClear(targetConfig.clearRegion());
+ if (mLayerManager->GetCompositor()) {
+ mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
+ }
+
+ mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig);
+ Layer* root = aLayerTree->GetRoot();
+ mLayerManager->SetRoot(root);
+
+ if (mApzUpdater && !aInfo.isRepeatTransaction()) {
+ mApzUpdater->UpdateFocusState(mRootLayerTreeID, mRootLayerTreeID,
+ aInfo.focusTarget());
+
+ if (aHitTestUpdate) {
+ AutoResolveRefLayers resolve(mCompositionManager);
+
+ mApzUpdater->UpdateHitTestingTree(root, aInfo.isFirstPaint(),
+ mRootLayerTreeID,
+ aInfo.paintSequenceNumber());
+ }
+ }
+
+ // The transaction ID might get reset to 1 if the page gets reloaded, see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
+ // Otherwise, it should be continually increasing.
+ MOZ_ASSERT(aInfo.id() == TransactionId{1} || mPendingTransactions.IsEmpty() ||
+ aInfo.id() > mPendingTransactions.LastElement());
+ mPendingTransactions.AppendElement(aInfo.id());
+ mRefreshStartTime = aInfo.refreshStart();
+ mTxnStartTime = aInfo.transactionStart();
+ mFwdTime = aInfo.fwdTime();
+ RegisterPayloads(aLayerTree, aInfo.payload());
+
+ if (root) {
+ SetShadowProperties(root);
+ }
+ if (aInfo.scheduleComposite()) {
+ ScheduleComposition();
+ if (mPaused) {
+ TimeStamp now = TimeStamp::Now();
+ DidComposite(VsyncId(), now, now);
+ }
+ }
+ mLayerManager->NotifyShadowTreeTransaction();
+}
+
+void CompositorBridgeParent::ScheduleComposite(
+ LayerTransactionParent* aLayerTree) {
+ ScheduleComposition();
+}
+
bool CompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
const TimeStamp& aTime) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
@@ -1035,6 +1222,34 @@ void CompositorBridgeParent::LeaveTestMode(const LayersId& aId) {
}
}
+void CompositorBridgeParent::ApplyAsyncProperties(
+ LayerTransactionParent* aLayerTree, TransformsToSkip aSkip) {
+ // NOTE: This should only be used for testing. For example, when mTestTime is
+ // non-empty, or when called from test-only methods like
+ // LayerTransactionParent::RecvGetAnimationTransform.
+
+ // Synchronously update the layer tree
+ if (aLayerTree->GetRoot()) {
+ AutoResolveRefLayers resolve(mCompositionManager);
+ SetShadowProperties(mLayerManager->GetRoot());
+
+ SampleTime time;
+ if (mTestTime) {
+ time = SampleTime::FromTest(*mTestTime);
+ } else {
+ time = mCompositorScheduler->GetLastComposeTime();
+ }
+ bool requestNextFrame =
+ mCompositionManager->TransformShadowTree(time, mVsyncRate, aSkip);
+ if (!requestNextFrame) {
+ CancelCurrentCompositeTask();
+ // Pretend we composited in case someone is waiting for this event.
+ TimeStamp now = TimeStamp::Now();
+ DidComposite(VsyncId(), now, now);
+ }
+ }
+}
+
CompositorAnimationStorage* CompositorBridgeParent::GetAnimationStorage() {
if (!mAnimationStorage) {
mAnimationStorage = new CompositorAnimationStorage(this);
@@ -1132,8 +1347,8 @@ void CompositorBridgeParent::SetConfirmedTargetAPZC(
void CompositorBridgeParent::SetFixedLayerMargins(ScreenIntCoord aTop,
ScreenIntCoord aBottom) {
- if (mCompositionManager) {
- mCompositionManager->SetFixedLayerMargins(aTop, aBottom);
+ if (AsyncCompositionManager* manager = GetCompositionManager(nullptr)) {
+ manager->SetFixedLayerMargins(aTop, aBottom);
}
if (mApzcTreeManager) {
@@ -1239,6 +1454,44 @@ RefPtr CompositorBridgeParent::NewCompositor(
return nullptr;
}
+PLayerTransactionParent* CompositorBridgeParent::AllocPLayerTransactionParent(
+ const nsTArray& aBackendHints, const LayersId& aId) {
+ MOZ_ASSERT(!aId.IsValid());
+
+#ifdef XP_WIN
+ // This is needed to avoid freezing the window on a device crash on double
+ // buffering, see bug 1549674.
+ if (gfxVars::UseDoubleBufferingWithCompositor() && XRE_IsGPUProcess() &&
+ aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) {
+ mWidget->AsWindows()->EnsureCompositorWindow();
+ }
+#endif
+
+ InitializeLayerManager(aBackendHints);
+
+ if (!mLayerManager) {
+ NS_WARNING("Failed to initialise Compositor");
+ LayerTransactionParent* p = new LayerTransactionParent(
+ /* aManager */ nullptr, this, /* aAnimStorage */ nullptr,
+ mRootLayerTreeID, mVsyncRate);
+ p->AddIPDLReference();
+ return p;
+ }
+
+ mCompositionManager = new AsyncCompositionManager(this, mLayerManager);
+
+ LayerTransactionParent* p = new LayerTransactionParent(
+ mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate);
+ p->AddIPDLReference();
+ return p;
+}
+
+bool CompositorBridgeParent::DeallocPLayerTransactionParent(
+ PLayerTransactionParent* actor) {
+ static_cast(actor)->ReleaseIPDLReference();
+ return true;
+}
+
CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(
uint64_t id) {
AssertIsInCompositorThread();
@@ -1423,6 +1676,14 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater;
}
NotifyChildCreated(child);
+ if (sIndirectLayerTrees[child].mLayerTree) {
+ sIndirectLayerTrees[child].mLayerTree->SetLayerManager(
+ mLayerManager, GetAnimationStorage());
+ // Trigger composition to handle a case that mLayerTree was not composited
+ // yet by previous CompositorBridgeParent, since nsRefreshDriver might
+ // wait composition complete.
+ scheduleComposition = true;
+ }
if (mWrBridge) {
childWrBridge = sIndirectLayerTrees[child].mWrBridge;
}
@@ -1884,6 +2145,22 @@ bool CompositorBridgeParent::DeallocPCompositorWidgetParent(
#endif
}
+bool CompositorBridgeParent::IsPendingComposite() {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ if (!mCompositor) {
+ return false;
+ }
+ return mCompositor->IsPendingComposite();
+}
+
+void CompositorBridgeParent::FinishPendingComposite() {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ if (!mCompositor) {
+ return;
+ }
+ return mCompositor->FinishPendingComposite();
+}
+
CompositorController*
CompositorBridgeParent::LayerTreeState::GetCompositorController() const {
return mParent;
diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h
index 7c73cdd9354a0..dd9fdbf6ccd48 100644
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -90,6 +90,7 @@ class GeckoContentController;
class HostLayerManager;
class IAPZCTreeManager;
class Layer;
+class LayerTransactionParent;
class OMTASampler;
class ContentCompositorBridgeParent;
class CompositorThreadHolder;
@@ -121,11 +122,25 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
public:
explicit CompositorBridgeParentBase(CompositorManagerParent* aManager);
+ virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const TransactionInfo& aInfo,
+ bool aHitTestUpdate) = 0;
+
+ virtual AsyncCompositionManager* GetCompositionManager(
+ LayerTransactionParent* aLayerTree) {
+ return nullptr;
+ }
+
+ virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) {}
+
+ virtual void ScheduleComposite(LayerTransactionParent* aLayerTree) {}
virtual bool SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) {
return true;
}
virtual void LeaveTestMode(const LayersId& aId) {}
enum class TransformsToSkip : uint8_t { NoneOfThem = 0, APZ = 1 };
+ virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+ TransformsToSkip aSkip) = 0;
virtual void SetTestAsyncScrollOffset(
const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
const CSSPoint& aPoint) = 0;
@@ -140,6 +155,10 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
virtual void SetConfirmedTargetAPZC(
const LayersId& aLayersId, const uint64_t& aInputBlockId,
nsTArray&& aTargets) = 0;
+ virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree,
+ const TimeDuration& aPaintTime) {}
+ virtual void RegisterPayloads(LayerTransactionParent* aLayerTree,
+ const nsTArray& aPayload) {}
IShmemAllocator* AsShmemAllocator() override { return this; }
@@ -211,6 +230,12 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
virtual bool DeallocPAPZCTreeManagerParent(
PAPZCTreeManagerParent* aActor) = 0;
+ virtual PLayerTransactionParent* AllocPLayerTransactionParent(
+ const nsTArray& layersBackendHints,
+ const LayersId& id) = 0;
+ virtual bool DeallocPLayerTransactionParent(
+ PLayerTransactionParent* aActor) = 0;
+
virtual PTextureParent* AllocPTextureParent(
const SurfaceDescriptor& aSharedData, const ReadLockDescriptor& aReadLock,
const LayersBackend& aBackend, const TextureFlags& aTextureFlags,
@@ -283,7 +308,8 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(
CompositorBridgeParentBase::TransformsToSkip)
class CompositorBridgeParent final : public CompositorBridgeParentBase,
- public CompositorController {
+ public CompositorController,
+ public CompositorVsyncSchedulerOwner {
friend class CompositorThreadHolder;
friend class InProcessCompositorSession;
friend class gfx::GPUProcessManager;
@@ -358,8 +384,14 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void ActorDestroy(ActorDestroyReason why) override;
+ void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const TransactionInfo& aInfo,
+ bool aHitTestUpdate) override;
+ void ScheduleComposite(LayerTransactionParent* aLayerTree) override;
bool SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) override;
void LeaveTestMode(const LayersId& aId) override;
+ void ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+ TransformsToSkip aSkip) override;
CompositorAnimationStorage* GetAnimationStorage();
using JankedAnimations =
std::unordered_map, LayersId::HashFn>;
@@ -378,6 +410,10 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void SetConfirmedTargetAPZC(
const LayersId& aLayersId, const uint64_t& aInputBlockId,
nsTArray&& aTargets) override;
+ AsyncCompositionManager* GetCompositionManager(
+ LayerTransactionParent* aLayerTree) override {
+ return mCompositionManager;
+ }
void SetFixedLayerMargins(ScreenIntCoord aTop, ScreenIntCoord aBottom);
PTextureParent* AllocPTextureParent(
@@ -443,6 +479,11 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
bool aIsRepeatTransaction,
bool aHitTestUpdate);
+ void UpdatePaintTime(LayerTransactionParent* aLayerTree,
+ const TimeDuration& aPaintTime) override;
+ void RegisterPayloads(LayerTransactionParent* aLayerTree,
+ const nsTArray& aPayload) override;
+
/**
* Check rotation info and schedule a rendering task if needed.
* Only can be called from compositor thread.
@@ -506,6 +547,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
// the PCompositorBridgeChild
ContentCompositorBridgeParent* mContentCompositorBridgeParent;
TargetConfig mTargetConfig;
+ LayerTransactionParent* mLayerTree;
CompositorController* GetCompositorController() const;
MetricsSharingController* CrossProcessSharingController() const;
@@ -574,7 +616,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
CompositorOptions GetOptions() const { return mOptions; }
- TimeDuration GetVsyncInterval() const {
+ TimeDuration GetVsyncInterval() const override {
// the variable is called "rate" but really it's an interval
return mVsyncRate;
}
@@ -665,6 +707,12 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void DeferredDestroy();
+ PLayerTransactionParent* AllocPLayerTransactionParent(
+ const nsTArray& aBackendHints,
+ const LayersId& aId) override;
+ bool DeallocPLayerTransactionParent(
+ PLayerTransactionParent* aLayers) override;
+
void SetEGLSurfaceRect(int x, int y, int width, int height);
void InitializeLayerManager(const nsTArray& aBackendHints);
@@ -680,6 +728,12 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void ForceComposition();
void CancelCurrentCompositeTask();
+ // CompositorVsyncSchedulerOwner
+ bool IsPendingComposite() override;
+ void FinishPendingComposite() override;
+ void CompositeToTarget(VsyncId aId, gfx::DrawTarget* aTarget,
+ const gfx::IntRect* aRect = nullptr) override;
+
RefPtr NewCompositor(
const nsTArray& aBackendHints);
diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp
index daa7bbad16d9c..454b8487f3ed6 100644
--- a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp
@@ -8,6 +8,7 @@
#include // for uint64_t
+#include "LayerTransactionParent.h" // for LayerTransactionParent
#include "apz/src/APZCTreeManager.h" // for APZCTreeManager
#include "gfxUtils.h"
#ifdef XP_WIN
@@ -24,6 +25,7 @@
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayerTreeOwnerTracker.h"
+#include "mozilla/layers/PLayerTransactionParent.h"
#include "mozilla/layers/RemoteContentController.h"
#include "mozilla/layers/WebRenderBridgeParent.h"
#include "mozilla/layers/AsyncImagePipelineManager.h"
@@ -61,6 +63,57 @@ void ContentCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) {
&ContentCompositorBridgeParent::DeferredDestroy));
}
+PLayerTransactionParent*
+ContentCompositorBridgeParent::AllocPLayerTransactionParent(
+ const nsTArray&, const LayersId& aId) {
+ MOZ_ASSERT(aId.IsValid());
+
+ // Check to see if this child process has access to this layer tree.
+ if (!LayerTreeOwnerTracker::Get()->IsMapped(aId, OtherPid())) {
+ NS_ERROR(
+ "Unexpected layers id in AllocPLayerTransactionParent; dropping "
+ "message...");
+ return nullptr;
+ }
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+
+ CompositorBridgeParent::LayerTreeState* state = nullptr;
+ LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId);
+ if (sIndirectLayerTrees.end() != itr) {
+ state = &itr->second;
+ }
+
+ if (state && state->mLayerManager) {
+ state->mContentCompositorBridgeParent = this;
+ HostLayerManager* lm = state->mLayerManager;
+ CompositorAnimationStorage* animStorage =
+ state->mParent ? state->mParent->GetAnimationStorage() : nullptr;
+ TimeDuration vsyncRate =
+ state->mParent ? state->mParent->GetVsyncInterval() : TimeDuration();
+ LayerTransactionParent* p =
+ new LayerTransactionParent(lm, this, animStorage, aId, vsyncRate);
+ p->AddIPDLReference();
+ sIndirectLayerTrees[aId].mLayerTree = p;
+ return p;
+ }
+
+ NS_WARNING("Created child without a matching parent?");
+ LayerTransactionParent* p = new LayerTransactionParent(
+ /* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId,
+ TimeDuration());
+ p->AddIPDLReference();
+ return p;
+}
+
+bool ContentCompositorBridgeParent::DeallocPLayerTransactionParent(
+ PLayerTransactionParent* aLayers) {
+ LayerTransactionParent* slp = static_cast(aLayers);
+ EraseLayerState(slp->GetId());
+ static_cast(aLayers)->ReleaseIPDLReference();
+ return true;
+}
+
PAPZCTreeManagerParent*
ContentCompositorBridgeParent::AllocPAPZCTreeManagerParent(
const LayersId& aLayersId) {
@@ -267,15 +320,104 @@ mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvCheckContentOnlyTDR(
return IPC_OK();
};
+void ContentCompositorBridgeParent::ShadowLayersUpdated(
+ LayerTransactionParent* aLayerTree, const TransactionInfo& aInfo,
+ bool aHitTestUpdate) {
+ LayersId id = aLayerTree->GetId();
+
+ MOZ_ASSERT(id.IsValid());
+
+ CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return;
+ }
+ MOZ_ASSERT(state->mParent);
+ state->mParent->ScheduleRotationOnCompositorThread(aInfo.targetConfig(),
+ aInfo.isFirstPaint());
+
+ Layer* shadowRoot = aLayerTree->GetRoot();
+ if (shadowRoot) {
+ CompositorBridgeParent::SetShadowProperties(shadowRoot);
+ }
+ UpdateIndirectTree(id, shadowRoot, aInfo.targetConfig());
+
+ state->mParent->NotifyShadowTreeTransaction(
+ id, aInfo.isFirstPaint(), aInfo.focusTarget(), aInfo.scheduleComposite(),
+ aInfo.paintSequenceNumber(), aInfo.isRepeatTransaction(), aHitTestUpdate);
+
+ if (aLayerTree->ShouldParentObserveEpoch()) {
+ // Note that we send this through the window compositor, since this needs
+ // to reach the widget owning the tab.
+ Unused << state->mParent->SendObserveLayersUpdate(
+ id, aLayerTree->GetChildEpoch(), true);
+ }
+
+ auto endTime = TimeStamp::Now();
+ if (profiler_can_accept_markers()) {
+ profiler_add_marker(
+ "CONTENT_FULL_PAINT_TIME", geckoprofiler::category::GRAPHICS,
+ MarkerTiming::Interval(aInfo.transactionStart(), endTime),
+ baseprofiler::markers::ContentBuildMarker{});
+ }
+ Telemetry::Accumulate(
+ Telemetry::CONTENT_FULL_PAINT_TIME,
+ static_cast(
+ (endTime - aInfo.transactionStart()).ToMilliseconds()));
+
+ RegisterPayloads(aLayerTree, aInfo.payload());
+
+ aLayerTree->SetPendingTransactionId(
+ aInfo.id(), aInfo.vsyncId(), aInfo.vsyncStart(), aInfo.refreshStart(),
+ aInfo.transactionStart(), endTime, aInfo.containsSVG(), aInfo.url(),
+ aInfo.fwdTime());
+}
+
void ContentCompositorBridgeParent::DidCompositeLocked(
LayersId aId, const VsyncId& aVsyncId, TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd) {
sIndirectLayerTreesLock->AssertCurrentThreadOwns();
- if (sIndirectLayerTrees[aId].mWrBridge) {
+ if (LayerTransactionParent* layerTree = sIndirectLayerTrees[aId].mLayerTree) {
+ nsTArray transactions;
+ layerTree->FlushPendingTransactions(aVsyncId, aCompositeEnd, transactions);
+ if (!transactions.IsEmpty()) {
+ Unused << SendDidComposite(aId, transactions, aCompositeStart,
+ aCompositeEnd);
+ }
+ } else if (sIndirectLayerTrees[aId].mWrBridge) {
MOZ_ASSERT(false); // this should never get called for a WR compositor
}
}
+void ContentCompositorBridgeParent::ScheduleComposite(
+ LayerTransactionParent* aLayerTree) {
+ LayersId id = aLayerTree->GetId();
+ MOZ_ASSERT(id.IsValid());
+ CompositorBridgeParent* parent;
+ { // scope lock
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ parent = sIndirectLayerTrees[id].mParent;
+ }
+ if (parent) {
+ parent->ScheduleComposite(aLayerTree);
+ }
+}
+
+void ContentCompositorBridgeParent::NotifyClearCachedResources(
+ LayerTransactionParent* aLayerTree) {
+ LayersId id = aLayerTree->GetId();
+ MOZ_ASSERT(id.IsValid());
+
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (state && state->mParent) {
+ // Note that we send this through the window compositor, since this needs
+ // to reach the widget owning the tab.
+ Unused << state->mParent->SendObserveLayersUpdate(
+ id, aLayerTree->GetChildEpoch(), false);
+ }
+}
+
bool ContentCompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
const TimeStamp& aTime) {
MOZ_ASSERT(aId.IsValid());
@@ -301,6 +443,20 @@ void ContentCompositorBridgeParent::LeaveTestMode(const LayersId& aId) {
state->mParent->LeaveTestMode(aId);
}
+void ContentCompositorBridgeParent::ApplyAsyncProperties(
+ LayerTransactionParent* aLayerTree, TransformsToSkip aSkip) {
+ LayersId id = aLayerTree->GetId();
+ MOZ_ASSERT(id.IsValid());
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ state->mParent->ApplyAsyncProperties(aLayerTree, aSkip);
+}
+
void ContentCompositorBridgeParent::SetTestAsyncScrollOffset(
const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
const CSSPoint& aPoint) {
@@ -379,6 +535,19 @@ void ContentCompositorBridgeParent::SetConfirmedTargetAPZC(
std::move(aTargets));
}
+AsyncCompositionManager* ContentCompositorBridgeParent::GetCompositionManager(
+ LayerTransactionParent* aLayerTree) {
+ LayersId id = aLayerTree->GetId();
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ return state->mParent->GetCompositionManager(aLayerTree);
+}
+
void ContentCompositorBridgeParent::DeferredDestroy() { mSelfRef = nullptr; }
ContentCompositorBridgeParent::~ContentCompositorBridgeParent() {
@@ -455,6 +624,35 @@ bool ContentCompositorBridgeParent::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}
+void ContentCompositorBridgeParent::UpdatePaintTime(
+ LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {
+ LayersId id = aLayerTree->GetId();
+ MOZ_ASSERT(id.IsValid());
+
+ CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state || !state->mParent) {
+ return;
+ }
+
+ state->mParent->UpdatePaintTime(aLayerTree, aPaintTime);
+}
+
+void ContentCompositorBridgeParent::RegisterPayloads(
+ LayerTransactionParent* aLayerTree,
+ const nsTArray& aPayload) {
+ LayersId id = aLayerTree->GetId();
+ MOZ_ASSERT(id.IsValid());
+
+ CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state || !state->mParent) {
+ return;
+ }
+
+ state->mParent->RegisterPayloads(aLayerTree, aPayload);
+}
+
void ContentCompositorBridgeParent::ObserveLayersUpdate(
LayersId aLayersId, LayersObserverEpoch aEpoch, bool aActive) {
MOZ_ASSERT(aLayersId.IsValid());
diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.h b/gfx/layers/ipc/ContentCompositorBridgeParent.h
index 579e69be50c83..bfdfd22237e35 100644
--- a/gfx/layers/ipc/ContentCompositorBridgeParent.h
+++ b/gfx/layers/ipc/ContentCompositorBridgeParent.h
@@ -108,8 +108,22 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
return IPC_OK();
}
+ PLayerTransactionParent* AllocPLayerTransactionParent(
+ const nsTArray& aBackendHints,
+ const LayersId& aId) override;
+
+ bool DeallocPLayerTransactionParent(
+ PLayerTransactionParent* aLayers) override;
+
+ void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const TransactionInfo& aInfo,
+ bool aHitTestUpdate) override;
+ void ScheduleComposite(LayerTransactionParent* aLayerTree) override;
+ void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) override;
bool SetTestSampleTime(const LayersId& aId, const TimeStamp& aTime) override;
void LeaveTestMode(const LayersId& aId) override;
+ void ApplyAsyncProperties(LayerTransactionParent* aLayerTree,
+ TransformsToSkip aSkip) override;
void SetTestAsyncScrollOffset(const LayersId& aLayersId,
const ScrollableLayerGuid::ViewID& aScrollId,
const CSSPoint& aPoint) override;
@@ -125,6 +139,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
const LayersId& aLayersId, const uint64_t& aInputBlockId,
nsTArray&& aTargets) override;
+ AsyncCompositionManager* GetCompositionManager(
+ LayerTransactionParent* aParent) override;
+
already_AddRefed AllocPWebGLParent() override;
// Use DidCompositeLocked if you already hold a lock on
@@ -166,6 +183,11 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
PAPZParent* AllocPAPZParent(const LayersId& aLayersId) override;
bool DeallocPAPZParent(PAPZParent* aActor) override;
+ void UpdatePaintTime(LayerTransactionParent* aLayerTree,
+ const TimeDuration& aPaintTime) override;
+ void RegisterPayloads(LayerTransactionParent* aLayerTree,
+ const nsTArray& aPayload) override;
+
PWebRenderBridgeParent* AllocPWebRenderBridgeParent(
const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize& aSize,
const WindowKind& aWindowKind) override;
diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp
index 92bad5111f8c1..0c3024426fa46 100644
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -11,6 +11,7 @@
#include "ImageBridgeParent.h" // for ImageBridgeParent
#include "ImageContainer.h" // for ImageContainer
#include "Layers.h" // for Layer, etc
+#include "ShadowLayers.h" // for ShadowLayerForwarder
#include "SynchronousTask.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
@@ -402,6 +403,10 @@ void ImageBridgeChild::EndTransaction() {
cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
}
+ if (!IsSameProcess()) {
+ ShadowLayerForwarder::PlatformSyncBeforeUpdate();
+ }
+
if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
NS_WARNING("could not send async texture transaction");
return;
diff --git a/gfx/layers/ipc/KnowsCompositor.cpp b/gfx/layers/ipc/KnowsCompositor.cpp
deleted file mode 100644
index 69c24d85f390d..0000000000000
--- a/gfx/layers/ipc/KnowsCompositor.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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/. */
-
-#include "KnowsCompositor.h"
-#include "mozilla/layers/ImageDataSerializer.h"
-#include "mozilla/layers/ImageBridgeChild.h"
-#include "mozilla/ipc/ProtocolUtils.h"
-
-namespace mozilla {
-namespace layers {
-
-void KnowsCompositor::IdentifyTextureHost(
- const TextureFactoryIdentifier& aIdentifier) {
- auto lock = mData.Lock();
- lock.ref().mTextureFactoryIdentifier = aIdentifier;
-
- lock.ref().mSyncObject =
- SyncObjectClient::CreateSyncObjectClientForContentDevice(
- aIdentifier.mSyncHandle);
-}
-
-KnowsCompositor::KnowsCompositor()
- : mData("KnowsCompositorMutex"), mSerial(++sSerialCounter) {}
-
-KnowsCompositor::~KnowsCompositor() = default;
-
-KnowsCompositorMediaProxy::KnowsCompositorMediaProxy(
- const TextureFactoryIdentifier& aIdentifier) {
- auto lock = mData.Lock();
- lock.ref().mTextureFactoryIdentifier = aIdentifier;
- // overwrite mSerial's value set by the parent class because we use the same
- // serial as the KnowsCompositor we are proxying.
- mThreadSafeAllocator = ImageBridgeChild::GetSingleton();
- lock.ref().mSyncObject = mThreadSafeAllocator->GetSyncObject();
-}
-
-KnowsCompositorMediaProxy::~KnowsCompositorMediaProxy() = default;
-
-TextureForwarder* KnowsCompositorMediaProxy::GetTextureForwarder() {
- return mThreadSafeAllocator->GetTextureForwarder();
-}
-
-LayersIPCActor* KnowsCompositorMediaProxy::GetLayersIPCActor() {
- return mThreadSafeAllocator->GetLayersIPCActor();
-}
-
-ActiveResourceTracker* KnowsCompositorMediaProxy::GetActiveResourceTracker() {
- return mThreadSafeAllocator->GetActiveResourceTracker();
-}
-
-void KnowsCompositorMediaProxy::SyncWithCompositor() {
- mThreadSafeAllocator->SyncWithCompositor();
-}
-
-bool IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface) {
- return aSurface.type() != SurfaceDescriptor::T__None &&
- aSurface.type() != SurfaceDescriptor::Tnull_t;
-}
-
-uint8_t* GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor) {
- MOZ_ASSERT(IsSurfaceDescriptorValid(aDescriptor));
- MOZ_RELEASE_ASSERT(
- aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer,
- "GFX: surface descriptor is not the right type.");
-
- auto memOrShmem = aDescriptor.get_SurfaceDescriptorBuffer().data();
- if (memOrShmem.type() == MemoryOrShmem::TShmem) {
- return memOrShmem.get_Shmem().get();
- } else {
- return reinterpret_cast(memOrShmem.get_uintptr_t());
- }
-}
-
-already_AddRefed GetSurfaceForDescriptor(
- const SurfaceDescriptor& aDescriptor) {
- if (aDescriptor.type() != SurfaceDescriptor::TSurfaceDescriptorBuffer) {
- return nullptr;
- }
- uint8_t* data = GetAddressFromDescriptor(aDescriptor);
- auto rgb =
- aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
- uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
- return gfx::Factory::CreateWrappingDataSourceSurface(data, stride, rgb.size(),
- rgb.format());
-}
-
-already_AddRefed GetDrawTargetForDescriptor(
- const SurfaceDescriptor& aDescriptor) {
- uint8_t* data = GetAddressFromDescriptor(aDescriptor);
- auto rgb =
- aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
- uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
- return gfx::Factory::CreateDrawTargetForData(
- gfx::BackendType::SKIA, data, rgb.size(), stride, rgb.format());
-}
-
-void DestroySurfaceDescriptor(IShmemAllocator* aAllocator,
- SurfaceDescriptor* aSurface) {
- MOZ_ASSERT(aSurface);
-
- SurfaceDescriptorBuffer& desc = aSurface->get_SurfaceDescriptorBuffer();
- switch (desc.data().type()) {
- case MemoryOrShmem::TShmem: {
- aAllocator->DeallocShmem(desc.data().get_Shmem());
- break;
- }
- case MemoryOrShmem::Tuintptr_t: {
- uint8_t* ptr = (uint8_t*)desc.data().get_uintptr_t();
- GfxMemoryImageReporter::WillFree(ptr);
- delete[] ptr;
- break;
- }
- default:
- MOZ_CRASH("surface type not implemented!");
- }
- *aSurface = SurfaceDescriptor();
-}
-
-} // namespace layers
-} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp
new file mode 100644
index 0000000000000..4dbd40e089908
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "LayerTransactionChild.h"
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "nsTArray.h" // for nsTArray
+#include "mozilla/layers/TextureClient.h"
+
+namespace mozilla {
+namespace layers {
+
+void LayerTransactionChild::Destroy() {
+ if (!IPCOpen()) {
+ return;
+ }
+ // mDestroyed is used to prevent calling Send__delete__() twice.
+ // When this function is called from CompositorBridgeChild::Destroy(),
+ // under Send__delete__() call, this function is called from
+ // ShadowLayerForwarder's destructor.
+ // When it happens, IPCOpen() is still true.
+ // See bug 1004191.
+ mDestroyed = true;
+
+ SendShutdown();
+}
+
+void LayerTransactionChild::ActorDestroy(ActorDestroyReason why) {
+ mDestroyed = true;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerTransactionChild.h b/gfx/layers/ipc/LayerTransactionChild.h
new file mode 100644
index 0000000000000..83ce36b02245f
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_LAYERTRANSACTIONCHILD_H
+#define MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
+
+#include // for uint32_t
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/PLayerTransactionChild.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+
+namespace layers {
+
+class ShadowLayerForwarder;
+
+class LayerTransactionChild : public PLayerTransactionChild {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LayerTransactionChild)
+ /**
+ * Clean this up, finishing with SendShutDown() which will cause __delete__
+ * to be sent from the parent side.
+ *
+ * It is expected (checked with an assert) that all shadow layers
+ * created by this have already been destroyed and
+ * Send__delete__()d by the time this method is called.
+ */
+ void Destroy();
+
+ bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
+ bool IsDestroyed() const { return mDestroyed; }
+
+ void SetForwarder(ShadowLayerForwarder* aForwarder) {
+ mForwarder = aForwarder;
+ }
+
+ LayersId GetId() const { return mId; }
+
+ void MarkDestroyed() { mDestroyed = true; }
+
+ protected:
+ explicit LayerTransactionChild(const LayersId& aId)
+ : mForwarder(nullptr), mIPCOpen(false), mDestroyed(false), mId(aId) {}
+ virtual ~LayerTransactionChild() = default;
+
+ void ActorDestroy(ActorDestroyReason why) override;
+
+ void AddIPDLReference() {
+ MOZ_ASSERT(mIPCOpen == false);
+ mIPCOpen = true;
+ AddRef();
+ }
+ void ReleaseIPDLReference() {
+ MOZ_ASSERT(mIPCOpen == true);
+ mIPCOpen = false;
+ Release();
+ }
+ friend class CompositorBridgeChild;
+
+ ShadowLayerForwarder* mForwarder;
+ bool mIPCOpen;
+ bool mDestroyed;
+ LayersId mId;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp
new file mode 100644
index 0000000000000..510cf0a431e3d
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -0,0 +1,1019 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "LayerTransactionParent.h"
+#include // for vector
+#include "CompositableHost.h" // for CompositableParent, Get, etc
+#include "ImageLayers.h" // for ImageLayer
+#include "Layers.h" // for Layer, ContainerLayer, etc
+#include "CompositableTransactionParent.h" // for EditReplyVector
+#include "CompositorBridgeParent.h"
+#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
+#include "mozilla/layers/AnimationHelper.h" // for GetAnimatedPropValue
+#include "mozilla/layers/CanvasLayerComposite.h"
+#include "mozilla/layers/ColorLayerComposite.h"
+#include "mozilla/layers/Compositor.h" // for Compositor
+#include "mozilla/layers/CompositorAnimationStorage.h" // for CompositorAnimationStorage
+#include "mozilla/layers/ContainerLayerComposite.h"
+#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
+#include "mozilla/layers/ImageLayerComposite.h"
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
+#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
+#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
+#include "mozilla/layers/PaintedLayerComposite.h"
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "mozilla/PerfStats.h"
+#include "mozilla/StaticPrefs_layers.h"
+#include "mozilla/StaticPrefs_layout.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/Unused.h"
+#include "nsCoord.h" // for NSAppUnitsToFloatPixels
+#include "nsISupportsImpl.h" // for Layer::Release, etc
+#include "nsLayoutUtils.h" // for nsLayoutUtils
+#include "nsMathUtils.h" // for NS_round
+#include "nsPoint.h" // for nsPoint
+#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
+#include "TreeTraversal.h" // for ForEachNode
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/ProfilerMarkers.h"
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/layers/AsyncCompositionManager.h"
+
+using mozilla::Telemetry::LABELS_CONTENT_FRAME_TIME_REASON;
+
+namespace mozilla {
+namespace layers {
+
+//--------------------------------------------------
+// LayerTransactionParent
+LayerTransactionParent::LayerTransactionParent(
+ HostLayerManager* aManager, CompositorBridgeParentBase* aBridge,
+ CompositorAnimationStorage* aAnimStorage, LayersId aId,
+ TimeDuration aVsyncRate)
+ : mLayerManager(aManager),
+ mCompositorBridge(aBridge),
+ mAnimStorage(aAnimStorage),
+ mId(aId),
+ mChildEpoch{0},
+ mParentEpoch{0},
+ mVsyncRate(aVsyncRate),
+ mDestroyed(false),
+ mIPCOpen(false),
+ mUpdateHitTestingTree(false) {
+ MOZ_ASSERT(mId.IsValid());
+}
+
+LayerTransactionParent::~LayerTransactionParent() = default;
+
+void LayerTransactionParent::SetLayerManager(
+ HostLayerManager* aLayerManager, CompositorAnimationStorage* aAnimStorage) {
+ if (mDestroyed) {
+ return;
+ }
+ mLayerManager = aLayerManager;
+ for (const auto& layer : mLayerMap.Values()) {
+ if (mAnimStorage && layer->GetCompositorAnimationsId()) {
+ mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
+ }
+ layer->AsHostLayer()->SetLayerManager(aLayerManager);
+ }
+ mAnimStorage = aAnimStorage;
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvShutdown() {
+ Destroy();
+ IProtocol* mgr = Manager();
+ if (!Send__delete__(this)) {
+ return IPC_FAIL_NO_REASON(mgr);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvShutdownSync() {
+ return RecvShutdown();
+}
+
+void LayerTransactionParent::Destroy() {
+ if (mDestroyed) {
+ return;
+ }
+ mDestroyed = true;
+ if (mAnimStorage) {
+ for (const auto& layer : mLayerMap.Values()) {
+ if (layer->GetCompositorAnimationsId()) {
+ mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
+ }
+ layer->Disconnect();
+ }
+ }
+ mCompositables.clear();
+ mAnimStorage = nullptr;
+}
+
+class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender final {
+ public:
+ explicit AutoLayerTransactionParentAsyncMessageSender(
+ LayerTransactionParent* aLayerTransaction,
+ const nsTArray* aDestroyActors = nullptr)
+ : mLayerTransaction(aLayerTransaction), mActorsToDestroy(aDestroyActors) {
+ mLayerTransaction->SetAboutToSendAsyncMessages();
+ }
+
+ ~AutoLayerTransactionParentAsyncMessageSender() {
+ mLayerTransaction->SendPendingAsyncMessages();
+ if (mActorsToDestroy) {
+ // Destroy the actors after sending the async messages because the latter
+ // may contain references to some actors.
+ for (const auto& op : *mActorsToDestroy) {
+ mLayerTransaction->DestroyActor(op);
+ }
+ }
+ }
+
+ private:
+ LayerTransactionParent* mLayerTransaction;
+ const nsTArray* mActorsToDestroy;
+};
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvPaintTime(
+ const TransactionId& aTransactionId, const TimeDuration& aPaintTime) {
+ mCompositorBridge->UpdatePaintTime(this, aPaintTime);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvUpdate(
+ const TransactionInfo& aInfo) {
+ AUTO_PROFILER_TRACING_MARKER("Paint", "LayerTransaction", GRAPHICS);
+ AUTO_PROFILER_LABEL("LayerTransactionParent::RecvUpdate", GRAPHICS);
+ PerfStats::AutoMetricRecording
+ autoRecording;
+
+ TimeStamp updateStart = TimeStamp::Now();
+
+ MOZ_LAYERS_LOG(
+ ("[ParentSide] received txn with %zu edits", aInfo.cset().Length()));
+
+ UpdateFwdTransactionId(aInfo.fwdTransactionId());
+
+ if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+ for (const auto& op : aInfo.toDestroy()) {
+ DestroyActor(op);
+ }
+ return IPC_OK();
+ }
+
+ // This ensures that destroy operations are always processed. It is not safe
+ // to early-return from RecvUpdate without doing so.
+ AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(
+ this, &aInfo.toDestroy());
+
+ {
+ AutoResolveRefLayers resolve(
+ mCompositorBridge->GetCompositionManager(this));
+ nsCString none;
+ mLayerManager->BeginTransaction(none);
+ }
+
+ // Not all edits require an update to the hit testing tree.
+ mUpdateHitTestingTree = false;
+
+ for (EditArray::index_type i = 0; i < aInfo.cset().Length(); ++i) {
+ const Edit& edit = const_cast(aInfo.cset()[i]);
+
+ switch (edit.type()) {
+ // Create* ops
+ case Edit::TOpCreatePaintedLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer"));
+
+ RefPtr layer = mLayerManager->CreatePaintedLayer();
+ if (!BindLayer(layer, edit.get_OpCreatePaintedLayer())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "CreatePaintedLayer");
+ break;
+ }
+ case Edit::TOpCreateContainerLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer"));
+
+ RefPtr layer = mLayerManager->CreateContainerLayer();
+ if (!BindLayer(layer, edit.get_OpCreateContainerLayer())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "CreateContainerLayer");
+ break;
+ }
+ case Edit::TOpCreateImageLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer"));
+
+ RefPtr layer = mLayerManager->CreateImageLayer();
+ if (!BindLayer(layer, edit.get_OpCreateImageLayer())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "CreateImageLayer");
+ break;
+ }
+ case Edit::TOpCreateColorLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer"));
+
+ RefPtr layer = mLayerManager->CreateColorLayer();
+ if (!BindLayer(layer, edit.get_OpCreateColorLayer())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "CreateColorLayer");
+ break;
+ }
+ case Edit::TOpCreateCanvasLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer"));
+
+ RefPtr layer = mLayerManager->CreateCanvasLayer();
+ if (!BindLayer(layer, edit.get_OpCreateCanvasLayer())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "CreateCanvasLayer");
+ break;
+ }
+ case Edit::TOpCreateRefLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer"));
+
+ RefPtr layer = mLayerManager->CreateRefLayer();
+ if (!BindLayer(layer, edit.get_OpCreateRefLayer())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "CreateRefLayer");
+ break;
+ }
+ case Edit::TOpSetDiagnosticTypes: {
+ mLayerManager->SetDiagnosticTypes(
+ edit.get_OpSetDiagnosticTypes().diagnostics());
+ break;
+ }
+ // Tree ops
+ case Edit::TOpSetRoot: {
+ MOZ_LAYERS_LOG(("[ParentSide] SetRoot"));
+
+ Layer* newRoot = AsLayer(edit.get_OpSetRoot().root());
+ if (!newRoot) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ if (newRoot->GetParent()) {
+ // newRoot is not a root!
+ return IPC_FAIL_NO_REASON(this);
+ }
+ mRoot = newRoot;
+
+ UpdateHitTestingTree(mRoot, "SetRoot");
+ break;
+ }
+ case Edit::TOpInsertAfter: {
+ MOZ_LAYERS_LOG(("[ParentSide] InsertAfter"));
+
+ const OpInsertAfter& oia = edit.get_OpInsertAfter();
+ Layer* child = AsLayer(oia.childLayer());
+ Layer* layer = AsLayer(oia.container());
+ Layer* after = AsLayer(oia.after());
+ if (!child || !layer || !after) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ ContainerLayer* container = layer->AsContainerLayer();
+ if (!container || !container->InsertAfter(child, after)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "InsertAfter");
+ break;
+ }
+ case Edit::TOpPrependChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] PrependChild"));
+
+ const OpPrependChild& oac = edit.get_OpPrependChild();
+ Layer* child = AsLayer(oac.childLayer());
+ Layer* layer = AsLayer(oac.container());
+ if (!child || !layer) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ ContainerLayer* container = layer->AsContainerLayer();
+ if (!container || !container->InsertAfter(child, nullptr)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "PrependChild");
+ break;
+ }
+ case Edit::TOpRemoveChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] RemoveChild"));
+
+ const OpRemoveChild& orc = edit.get_OpRemoveChild();
+ Layer* childLayer = AsLayer(orc.childLayer());
+ Layer* layer = AsLayer(orc.container());
+ if (!childLayer || !layer) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ ContainerLayer* container = layer->AsContainerLayer();
+ if (!container || !container->RemoveChild(childLayer)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "RemoveChild");
+ break;
+ }
+ case Edit::TOpRepositionChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] RepositionChild"));
+
+ const OpRepositionChild& orc = edit.get_OpRepositionChild();
+ Layer* child = AsLayer(orc.childLayer());
+ Layer* after = AsLayer(orc.after());
+ Layer* layer = AsLayer(orc.container());
+ if (!child || !layer || !after) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ ContainerLayer* container = layer->AsContainerLayer();
+ if (!container || !container->RepositionChild(child, after)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "RepositionChild");
+ break;
+ }
+ case Edit::TOpRaiseToTopChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] RaiseToTopChild"));
+
+ const OpRaiseToTopChild& rtc = edit.get_OpRaiseToTopChild();
+ Layer* child = AsLayer(rtc.childLayer());
+ if (!child) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ Layer* layer = AsLayer(rtc.container());
+ if (!layer) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ ContainerLayer* container = layer->AsContainerLayer();
+ if (!container || !container->RepositionChild(child, nullptr)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ UpdateHitTestingTree(layer, "RaiseToTopChild");
+ break;
+ }
+ case Edit::TCompositableOperation: {
+ if (!ReceiveCompositableUpdate(edit.get_CompositableOperation())) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ break;
+ }
+ case Edit::TOpAttachCompositable: {
+ const OpAttachCompositable& op = edit.get_OpAttachCompositable();
+ RefPtr host = FindCompositable(op.compositable());
+ if (!Attach(AsLayer(op.layer()), host, false)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ host->SetCompositorBridgeID(mLayerManager->GetCompositorBridgeID());
+ break;
+ }
+ case Edit::TOpAttachAsyncCompositable: {
+ const OpAttachAsyncCompositable& op =
+ edit.get_OpAttachAsyncCompositable();
+ RefPtr imageBridge =
+ ImageBridgeParent::GetInstance(OtherPid());
+ if (!imageBridge) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ RefPtr host = imageBridge->FindCompositable(
+ op.compositable(), /* aAllowDisablingWebRender */ true);
+ if (!host) {
+ // This normally should not happen, but can after a GPU process crash.
+ // Media may not have had time to update the ImageContainer associated
+ // with a video frame, and we may try to attach a stale
+ // CompositableHandle. Rather than break the whole transaction, we
+ // just continue.
+ gfxCriticalNote << "CompositableHost " << op.compositable().Value()
+ << " not found";
+ continue;
+ }
+ if (!Attach(AsLayer(op.layer()), host, true)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ host->SetCompositorBridgeID(mLayerManager->GetCompositorBridgeID());
+ break;
+ }
+ default:
+ MOZ_CRASH("not reached");
+ }
+ }
+
+ // Process simple attribute updates.
+ for (const auto& op : aInfo.setSimpleAttrs()) {
+ MOZ_LAYERS_LOG(("[ParentSide] SetSimpleLayerAttributes"));
+ Layer* layer = AsLayer(op.layer());
+ if (!layer) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ const SimpleLayerAttributes& attrs = op.attrs();
+ const SimpleLayerAttributes& orig = layer->GetSimpleAttributes();
+ if (!attrs.HitTestingInfoIsEqual(orig)) {
+ UpdateHitTestingTree(layer, "scrolling info changed");
+ }
+ layer->SetSimpleAttributes(op.attrs());
+ }
+
+ // Process attribute updates.
+ for (const auto& op : aInfo.setAttrs()) {
+ MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes"));
+ if (!SetLayerAttributes(op)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ }
+
+ // Process paints separately, after all normal edits.
+ for (const auto& op : aInfo.paints()) {
+ if (!ReceiveCompositableUpdate(op)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ }
+
+ mCompositorBridge->ShadowLayersUpdated(this, aInfo, mUpdateHitTestingTree);
+
+ {
+ AutoResolveRefLayers resolve(
+ mCompositorBridge->GetCompositionManager(this));
+ mLayerManager->EndTransaction(TimeStamp(),
+ LayerManager::END_NO_IMMEDIATE_REDRAW);
+ }
+
+ if (!IsSameProcess()) {
+ // Ensure that any pending operations involving back and front
+ // buffers have completed, so that neither process stomps on the
+ // other's buffer contents.
+ LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
+ }
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ int compositeTime =
+ (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds();
+ if (compositeTime > 15) {
+ printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n",
+ compositeTime);
+ }
+#endif
+
+ // Enable visual warning for long transaction when draw FPS option is enabled
+ bool drawFps = StaticPrefs::layers_acceleration_draw_fps();
+ if (drawFps) {
+ uint32_t visualWarningTrigger =
+ StaticPrefs::layers_transaction_warning_ms();
+ // The default theshold is 200ms to trigger, hit red when it take 4 times
+ // longer
+ TimeDuration latency = TimeStamp::Now() - aInfo.transactionStart();
+ if (latency > TimeDuration::FromMilliseconds(visualWarningTrigger)) {
+ float severity =
+ (latency - TimeDuration::FromMilliseconds(visualWarningTrigger))
+ .ToMilliseconds() /
+ (4 * visualWarningTrigger);
+ if (severity > 1.f) {
+ severity = 1.f;
+ }
+ mLayerManager->VisualFrameWarning(severity);
+ printf_stderr(
+ "LayerTransactionParent::RecvUpdate transaction from process %d took "
+ "%f ms",
+ OtherPid(), latency.ToMilliseconds());
+ }
+
+ mLayerManager->RecordUpdateTime(
+ (TimeStamp::Now() - updateStart).ToMilliseconds());
+ }
+
+ return IPC_OK();
+}
+
+bool LayerTransactionParent::SetLayerAttributes(
+ const OpSetLayerAttributes& aOp) {
+ Layer* layer = AsLayer(aOp.layer());
+ if (!layer) {
+ return false;
+ }
+
+ const LayerAttributes& attrs = aOp.attrs();
+ const CommonLayerAttributes& common = attrs.common();
+ if (common.visibleRegion() != layer->GetVisibleRegion()) {
+ UpdateHitTestingTree(layer, "visible region changed");
+ layer->SetVisibleRegion(common.visibleRegion());
+ }
+ if (common.eventRegions() != layer->GetEventRegions()) {
+ UpdateHitTestingTree(layer, "event regions changed");
+ layer->SetEventRegions(common.eventRegions());
+ }
+ Maybe clipRect =
+ common.useClipRect() ? Some(common.clipRect()) : Nothing();
+ if (clipRect != layer->GetClipRect()) {
+ UpdateHitTestingTree(layer, "clip rect changed");
+ layer->SetClipRect(clipRect);
+ }
+ if (LayerHandle maskLayer = common.maskLayer()) {
+ layer->SetMaskLayer(AsLayer(maskLayer));
+ } else {
+ layer->SetMaskLayer(nullptr);
+ }
+ layer->SetCompositorAnimations(mId, common.compositorAnimations());
+ // Clean up the Animations by id in the CompositorAnimationStorage
+ // if there are no active animations on the layer
+ if (mAnimStorage && layer->GetCompositorAnimationsId() &&
+ layer->GetPropertyAnimationGroups().IsEmpty()) {
+ mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
+ }
+ if (common.scrollMetadata() != layer->GetAllScrollMetadata()) {
+ UpdateHitTestingTree(layer, "scroll metadata changed");
+ layer->SetScrollMetadata(common.scrollMetadata());
+ }
+ layer->SetDisplayListLog(common.displayListLog().get());
+
+ // The updated invalid region is added to the existing one, since we can
+ // update multiple times before the next composite.
+ layer->AddInvalidRegion(common.invalidRegion());
+
+ nsTArray> maskLayers;
+ for (size_t i = 0; i < common.ancestorMaskLayers().Length(); i++) {
+ Layer* maskLayer = AsLayer(common.ancestorMaskLayers().ElementAt(i));
+ if (!maskLayer) {
+ return false;
+ }
+ maskLayers.AppendElement(maskLayer);
+ }
+ layer->SetAncestorMaskLayers(maskLayers);
+
+ typedef SpecificLayerAttributes Specific;
+ const SpecificLayerAttributes& specific = attrs.specific();
+ switch (specific.type()) {
+ case Specific::Tnull_t:
+ break;
+
+ case Specific::TPaintedLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] painted layer"));
+
+ PaintedLayer* paintedLayer = layer->AsPaintedLayer();
+ if (!paintedLayer) {
+ return false;
+ }
+ const PaintedLayerAttributes& attrs =
+ specific.get_PaintedLayerAttributes();
+
+ paintedLayer->SetValidRegion(attrs.validRegion());
+ break;
+ }
+ case Specific::TContainerLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] container layer"));
+
+ ContainerLayer* containerLayer = layer->AsContainerLayer();
+ if (!containerLayer) {
+ return false;
+ }
+ const ContainerLayerAttributes& attrs =
+ specific.get_ContainerLayerAttributes();
+ containerLayer->SetPreScale(attrs.preXScale(), attrs.preYScale());
+ containerLayer->SetInheritedScale(attrs.inheritedXScale(),
+ attrs.inheritedYScale());
+ containerLayer->SetScaleToResolution(attrs.presShellResolution());
+ break;
+ }
+ case Specific::TColorLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] color layer"));
+
+ ColorLayer* colorLayer = layer->AsColorLayer();
+ if (!colorLayer) {
+ return false;
+ }
+ colorLayer->SetColor(specific.get_ColorLayerAttributes().color().value());
+ colorLayer->SetBounds(specific.get_ColorLayerAttributes().bounds());
+ break;
+ }
+ case Specific::TCanvasLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] canvas layer"));
+
+ CanvasLayer* canvasLayer = layer->AsCanvasLayer();
+ if (!canvasLayer) {
+ return false;
+ }
+ canvasLayer->SetSamplingFilter(
+ specific.get_CanvasLayerAttributes().samplingFilter());
+ canvasLayer->SetBounds(specific.get_CanvasLayerAttributes().bounds());
+ break;
+ }
+ case Specific::TRefLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] ref layer"));
+
+ RefLayer* refLayer = layer->AsRefLayer();
+ if (!refLayer) {
+ return false;
+ }
+ refLayer->SetReferentId(specific.get_RefLayerAttributes().id());
+ refLayer->SetEventRegionsOverride(
+ specific.get_RefLayerAttributes().eventRegionsOverride());
+ refLayer->SetRemoteDocumentSize(
+ specific.get_RefLayerAttributes().remoteDocumentSize());
+ UpdateHitTestingTree(layer, "ref layer attributes changed");
+ break;
+ }
+ case Specific::TImageLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] image layer"));
+
+ ImageLayer* imageLayer = layer->AsImageLayer();
+ if (!imageLayer) {
+ return false;
+ }
+ const ImageLayerAttributes& attrs = specific.get_ImageLayerAttributes();
+ imageLayer->SetSamplingFilter(attrs.samplingFilter());
+ imageLayer->SetScaleToSize(attrs.scaleToSize(), attrs.scaleMode());
+ break;
+ }
+ default:
+ MOZ_CRASH("not reached");
+ }
+
+ return true;
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvSetLayersObserverEpoch(
+ const LayersObserverEpoch& aChildEpoch) {
+ mChildEpoch = aChildEpoch;
+ return IPC_OK();
+}
+
+bool LayerTransactionParent::ShouldParentObserveEpoch() {
+ if (mParentEpoch == mChildEpoch) {
+ return false;
+ }
+
+ mParentEpoch = mChildEpoch;
+ return true;
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvSetTestSampleTime(
+ const TimeStamp& aTime) {
+ if (!mCompositorBridge->SetTestSampleTime(GetId(), aTime)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvLeaveTestMode() {
+ if (mDestroyed) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ mCompositorBridge->LeaveTestMode(GetId());
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvGetAnimationValue(
+ const uint64_t& aCompositorAnimationsId, OMTAValue* aValue) {
+ if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ // Make sure we apply the latest animation style or else we can end up with
+ // a race between when we temporarily clear the animation transform (in
+ // CompositorBridgeParent::SetShadowProperties) and when animation
+ // recalculates the value.
+ mCompositorBridge->ApplyAsyncProperties(
+ this, CompositorBridgeParentBase::TransformsToSkip::APZ);
+
+ if (!mAnimStorage) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ *aValue = mAnimStorage->GetOMTAValue(aCompositorAnimationsId);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvGetTransform(
+ const LayerHandle& aLayerHandle, Maybe* aTransform) {
+ if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ Layer* layer = AsLayer(aLayerHandle);
+ if (!layer) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ mCompositorBridge->ApplyAsyncProperties(
+ this, CompositorBridgeParentBase::TransformsToSkip::NoneOfThem);
+
+ Matrix4x4 transform = layer->AsHostLayer()->GetShadowBaseTransform();
+ // Undo the scale transform applied by FrameTransformToTransformInDevice in
+ // AsyncCompositionManager.cpp.
+ if (ContainerLayer* c = layer->AsContainerLayer()) {
+ transform.PostScale(1.0f / c->GetInheritedXScale(),
+ 1.0f / c->GetInheritedYScale(), 1.0f);
+ }
+ float scale = 1;
+ Point3D scaledOrigin;
+ if (layer->GetTransformData()) {
+ const TransformData& data = *layer->GetTransformData();
+ scale = data.appUnitsPerDevPixel();
+ scaledOrigin = Point3D(
+ NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)),
+ NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)), 0.0f);
+ }
+
+ // If our parent isn't a perspective layer, then the offset into reference
+ // frame coordinates will have been applied to us. Add an inverse translation
+ // to cancel it out.
+ if (!layer->GetParent() || !layer->GetParent()->GetTransformIsPerspective()) {
+ transform.PostTranslate(-scaledOrigin.x, -scaledOrigin.y, -scaledOrigin.z);
+ }
+
+ *aTransform = Some(transform);
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvSetAsyncScrollOffset(
+ const ScrollableLayerGuid::ViewID& aScrollID, const float& aX,
+ const float& aY) {
+ if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ mCompositorBridge->SetTestAsyncScrollOffset(GetId(), aScrollID,
+ CSSPoint(aX, aY));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvSetAsyncZoom(
+ const ScrollableLayerGuid::ViewID& aScrollID, const float& aValue) {
+ if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ mCompositorBridge->SetTestAsyncZoom(GetId(), aScrollID,
+ LayerToParentLayerScale(aValue));
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvFlushApzRepaints() {
+ mCompositorBridge->FlushApzRepaints(GetId());
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvGetAPZTestData(
+ APZTestData* aOutData) {
+ mCompositorBridge->GetAPZTestData(GetId(), aOutData);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvGetFrameUniformity(
+ FrameUniformityData* aOutData) {
+ mCompositorBridge->GetFrameUniformity(GetId(), aOutData);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvRequestProperty(
+ const nsString& aProperty, float* aValue) {
+ *aValue = -1;
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvSetConfirmedTargetAPZC(
+ const uint64_t& aBlockId, nsTArray&& aTargets) {
+ for (size_t i = 0; i < aTargets.Length(); i++) {
+ // Guard against bad data from hijacked child processes
+ if (aTargets[i].mLayersId != GetId()) {
+ NS_ERROR(
+ "Unexpected layers id in RecvSetConfirmedTargetAPZC; dropping "
+ "message...");
+ return IPC_FAIL(this, "Bad layers id");
+ }
+ }
+ mCompositorBridge->SetConfirmedTargetAPZC(GetId(), aBlockId,
+ std::move(aTargets));
+ return IPC_OK();
+}
+
+bool LayerTransactionParent::Attach(Layer* aLayer,
+ CompositableHost* aCompositable,
+ bool aIsAsync) {
+ if (!aCompositable || !aLayer) {
+ return false;
+ }
+
+ HostLayer* layer = aLayer->AsHostLayer();
+ if (!layer) {
+ return false;
+ }
+
+ TextureSourceProvider* provider =
+ static_cast(aLayer->Manager())
+ ->GetTextureSourceProvider();
+
+ MOZ_ASSERT(!aCompositable->AsWebRenderImageHost());
+ if (aCompositable->AsWebRenderImageHost()) {
+ gfxCriticalNote << "Use WebRenderImageHost at LayerTransactionParent.";
+ }
+ if (!layer->SetCompositableHost(aCompositable)) {
+ // not all layer types accept a compositable, see bug 967824
+ return false;
+ }
+ aCompositable->Attach(aLayer, provider,
+ aIsAsync ? CompositableHost::ALLOW_REATTACH |
+ CompositableHost::KEEP_ATTACHED
+ : CompositableHost::NO_FLAGS);
+ return true;
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvClearCachedResources() {
+ if (mRoot) {
+ // NB: |mRoot| here is the *child* context's root. In this parent
+ // context, it's just a subtree root. We need to scope the clear
+ // of resources to exactly that subtree, so we specify it here.
+ mLayerManager->ClearCachedResources(mRoot);
+ }
+ mCompositorBridge->NotifyClearCachedResources(this);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvScheduleComposite() {
+ mCompositorBridge->ScheduleComposite(this);
+ return IPC_OK();
+}
+
+void LayerTransactionParent::ActorDestroy(ActorDestroyReason why) { Destroy(); }
+
+bool LayerTransactionParent::AllocShmem(
+ size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) {
+ if (!mIPCOpen || mDestroyed) {
+ return false;
+ }
+ return PLayerTransactionParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool LayerTransactionParent::AllocUnsafeShmem(
+ size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) {
+ if (!mIPCOpen || mDestroyed) {
+ return false;
+ }
+
+ return PLayerTransactionParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+bool LayerTransactionParent::DeallocShmem(ipc::Shmem& aShmem) {
+ if (!mIPCOpen || mDestroyed) {
+ return false;
+ }
+ return PLayerTransactionParent::DeallocShmem(aShmem);
+}
+
+bool LayerTransactionParent::IsSameProcess() const {
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void LayerTransactionParent::SetPendingTransactionId(
+ TransactionId aId, const VsyncId& aVsyncId,
+ const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
+ const TimeStamp& aTxnStartTime, const TimeStamp& aTxnEndTime,
+ bool aContainsSVG, const nsCString& aURL, const TimeStamp& aFwdTime) {
+ mPendingTransactions.AppendElement(PendingTransaction{
+ aId, aVsyncId, aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
+ aTxnEndTime, aFwdTime, aURL, aContainsSVG});
+}
+
+void LayerTransactionParent::FlushPendingTransactions(
+ const VsyncId& aCompositeId, TimeStamp& aCompositeEnd,
+ nsTArray& aOutTransactions) {
+ for (auto& transaction : mPendingTransactions) {
+ aOutTransactions.AppendElement(transaction.mId);
+ if (mId.IsValid() && transaction.mId.IsValid() && !mVsyncRate.IsZero()) {
+ RecordContentFrameTime(
+ transaction.mTxnVsyncId, transaction.mVsyncStartTime,
+ transaction.mTxnStartTime, aCompositeId, aCompositeEnd,
+ transaction.mTxnEndTime - transaction.mTxnStartTime, mVsyncRate,
+ transaction.mContainsSVG, false);
+ }
+
+#if defined(ENABLE_FRAME_LATENCY_LOG)
+ if (transaction.mId.IsValid()) {
+ if (transaction.mRefreshStartTime) {
+ int32_t latencyMs = lround(
+ (aCompositeEnd - transaction.mRefreshStartTime).ToMilliseconds());
+ printf_stderr(
+ "From transaction start to end of generate frame latencyMs %d this "
+ "%p\n",
+ latencyMs, this);
+ }
+ if (transaction.mFwdTime) {
+ int32_t latencyMs =
+ lround((aCompositeEnd - transaction.mFwdTime).ToMilliseconds());
+ printf_stderr(
+ "From forwarding transaction to end of generate frame latencyMs %d "
+ "this %p\n",
+ latencyMs, this);
+ }
+ }
+#endif
+ }
+
+ mPendingTransactions.Clear();
+}
+
+void LayerTransactionParent::SendAsyncMessage(
+ const nsTArray& aMessage) {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+void LayerTransactionParent::SendPendingAsyncMessages() {
+ mCompositorBridge->SendPendingAsyncMessages();
+}
+
+void LayerTransactionParent::SetAboutToSendAsyncMessages() {
+ mCompositorBridge->SetAboutToSendAsyncMessages();
+}
+
+void LayerTransactionParent::NotifyNotUsed(PTextureParent* aTexture,
+ uint64_t aTransactionId) {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+bool LayerTransactionParent::BindLayerToHandle(RefPtr aLayer,
+ const LayerHandle& aHandle) {
+ if (!aHandle || !aLayer) {
+ return false;
+ }
+ return mLayerMap.WithEntryHandle(aHandle.Value(), [&](auto&& entry) {
+ if (entry) {
+ return false;
+ }
+ entry.Insert(std::move(aLayer));
+ return true;
+ });
+}
+
+Layer* LayerTransactionParent::AsLayer(const LayerHandle& aHandle) {
+ if (!aHandle) {
+ return nullptr;
+ }
+ return mLayerMap.GetWeak(aHandle.Value());
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvNewCompositable(
+ const CompositableHandle& aHandle, const TextureInfo& aInfo) {
+ if (!AddCompositable(aHandle, aInfo, /* aUseWebRender */ false)) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvReleaseLayer(
+ const LayerHandle& aHandle) {
+ RefPtr layer;
+ if (!aHandle || !mLayerMap.Remove(aHandle.Value(), getter_AddRefs(layer))) {
+ return IPC_FAIL_NO_REASON(this);
+ }
+ if (mAnimStorage && layer->GetCompositorAnimationsId()) {
+ mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
+ layer->ClearCompositorAnimations();
+ }
+ layer->Disconnect();
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvReleaseCompositable(
+ const CompositableHandle& aHandle) {
+ ReleaseCompositable(aHandle);
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvRecordPaintTimes(
+ const PaintTiming& aTiming) {
+ // Currently we only add paint timings for remote layers. In the future
+ // we could be smarter and use paint timings from the UI process, either
+ // as a separate overlay or if no remote layers are attached.
+ if (mLayerManager && mCompositorBridge->IsRemote()) {
+ mLayerManager->RecordPaintTimes(aTiming);
+ }
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult LayerTransactionParent::RecvGetTextureFactoryIdentifier(
+ TextureFactoryIdentifier* aIdentifier) {
+ if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
+ // Default constructor sets mParentBackend to LAYERS_NONE.
+ return IPC_OK();
+ }
+
+ *aIdentifier = mLayerManager->GetTextureFactoryIdentifier();
+ return IPC_OK();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h
new file mode 100644
index 0000000000000..417236729ae37
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_LAYERTRANSACTIONPARENT_H
+#define MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H
+
+#include // for size_t
+#include // for uint64_t, uint32_t
+#include "CompositableTransactionParent.h"
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/layers/PLayerTransactionParent.h"
+#include "nsRefPtrHashtable.h"
+#include "nsTArrayForwardDeclare.h" // for nsTArray
+
+namespace mozilla {
+
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+class Layer;
+class HostLayerManager;
+class ShadowLayerParent;
+class CompositableParent;
+class CompositorAnimationStorage;
+class CompositorBridgeParentBase;
+
+class LayerTransactionParent final : public PLayerTransactionParent,
+ public CompositableParentManager,
+ public mozilla::ipc::IShmemAllocator {
+ typedef nsTArray EditArray;
+ typedef nsTArray OpDestroyArray;
+
+ friend class PLayerTransactionParent;
+
+ public:
+ LayerTransactionParent(HostLayerManager* aManager,
+ CompositorBridgeParentBase* aBridge,
+ CompositorAnimationStorage* aAnimStorage, LayersId aId,
+ TimeDuration aVsyncRate);
+
+ protected:
+ virtual ~LayerTransactionParent();
+
+ public:
+ void Destroy();
+
+ void SetLayerManager(HostLayerManager* aLayerManager,
+ CompositorAnimationStorage* aAnimStorage);
+
+ LayersId GetId() const { return mId; }
+ Layer* GetRoot() const { return mRoot; }
+
+ LayersObserverEpoch GetChildEpoch() const { return mChildEpoch; }
+ bool ShouldParentObserveEpoch();
+
+ IShmemAllocator* AsShmemAllocator() override { return this; }
+
+ bool AllocShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ bool AllocUnsafeShmem(size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ bool DeallocShmem(ipc::Shmem& aShmem) override;
+
+ bool IsSameProcess() const override;
+
+ void SetPendingTransactionId(TransactionId aId, const VsyncId& aVsyncId,
+ const TimeStamp& aVsyncStartTime,
+ const TimeStamp& aRefreshStartTime,
+ const TimeStamp& aTxnStartTime,
+ const TimeStamp& aTxnEndTime, bool aContainsSVG,
+ const nsCString& aURL,
+ const TimeStamp& aFwdTime);
+ void FlushPendingTransactions(const VsyncId& aId, TimeStamp& aCompositeEnd,
+ nsTArray& aOutTransactions);
+
+ // CompositableParentManager
+ void SendAsyncMessage(
+ const nsTArray& aMessage) override;
+
+ void SendPendingAsyncMessages() override;
+
+ void SetAboutToSendAsyncMessages() override;
+
+ void NotifyNotUsed(PTextureParent* aTexture,
+ uint64_t aTransactionId) override;
+
+ base::ProcessId GetChildProcessId() override { return OtherPid(); }
+
+ protected:
+ mozilla::ipc::IPCResult RecvShutdown();
+ mozilla::ipc::IPCResult RecvShutdownSync();
+
+ mozilla::ipc::IPCResult RecvPaintTime(const TransactionId& aTransactionId,
+ const TimeDuration& aPaintTime);
+
+ mozilla::ipc::IPCResult RecvUpdate(const TransactionInfo& aInfo);
+
+ mozilla::ipc::IPCResult RecvSetLayersObserverEpoch(
+ const LayersObserverEpoch& aChildEpoch);
+ mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
+ const TextureInfo& aInfo);
+ mozilla::ipc::IPCResult RecvReleaseLayer(const LayerHandle& aHandle);
+ mozilla::ipc::IPCResult RecvReleaseCompositable(
+ const CompositableHandle& aHandle);
+
+ mozilla::ipc::IPCResult RecvClearCachedResources();
+ mozilla::ipc::IPCResult RecvScheduleComposite();
+ mozilla::ipc::IPCResult RecvSetTestSampleTime(const TimeStamp& aTime);
+ mozilla::ipc::IPCResult RecvLeaveTestMode();
+ mozilla::ipc::IPCResult RecvGetAnimationValue(
+ const uint64_t& aCompositorAnimationsId, OMTAValue* aValue);
+ mozilla::ipc::IPCResult RecvGetTransform(const LayerHandle& aHandle,
+ Maybe* aTransform);
+ mozilla::ipc::IPCResult RecvSetAsyncScrollOffset(
+ const ScrollableLayerGuid::ViewID& aId, const float& aX, const float& aY);
+ mozilla::ipc::IPCResult RecvSetAsyncZoom(
+ const ScrollableLayerGuid::ViewID& aId, const float& aValue);
+ mozilla::ipc::IPCResult RecvFlushApzRepaints();
+ mozilla::ipc::IPCResult RecvGetAPZTestData(APZTestData* aOutData);
+ mozilla::ipc::IPCResult RecvGetFrameUniformity(FrameUniformityData* aOutData);
+ mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty,
+ float* aValue);
+ mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(
+ const uint64_t& aBlockId, nsTArray&& aTargets);
+ mozilla::ipc::IPCResult RecvRecordPaintTimes(const PaintTiming& aTiming);
+ mozilla::ipc::IPCResult RecvGetTextureFactoryIdentifier(
+ TextureFactoryIdentifier* aIdentifier);
+
+ bool SetLayerAttributes(const OpSetLayerAttributes& aOp);
+
+ void ActorDestroy(ActorDestroyReason why) override;
+
+ template
+ bool BindLayer(const RefPtr& aLayer, const T& aCreateOp) {
+ return BindLayerToHandle(aLayer, aCreateOp.layer());
+ }
+
+ bool BindLayerToHandle(RefPtr aLayer, const LayerHandle& aHandle);
+
+ Layer* AsLayer(const LayerHandle& aLayer);
+
+ bool Attach(Layer* aLayer, CompositableHost* aCompositable,
+ bool aIsAsyncVideo);
+
+ void AddIPDLReference() {
+ MOZ_ASSERT(mIPCOpen == false);
+ mIPCOpen = true;
+ AddRef();
+ }
+ void ReleaseIPDLReference() {
+ MOZ_ASSERT(mIPCOpen == true);
+ mIPCOpen = false;
+ Release();
+ }
+ friend class CompositorBridgeParent;
+ friend class ContentCompositorBridgeParent;
+
+ private:
+ // This is a function so we can log or breakpoint on why hit
+ // testing tree changes are made.
+ void UpdateHitTestingTree(Layer* aLayer, const char* aWhy) {
+ mUpdateHitTestingTree = true;
+ }
+
+ private:
+ RefPtr mLayerManager;
+ CompositorBridgeParentBase* mCompositorBridge;
+ RefPtr mAnimStorage;
+
+ // Hold the root because it might be grafted under various
+ // containers in the "real" layer tree
+ RefPtr mRoot;
+
+ // Mapping from LayerHandles to Layers.
+ nsRefPtrHashtable mLayerMap;
+
+ LayersId mId;
+
+ // These fields keep track of the latest epoch values in the child and the
+ // parent. mChildEpoch is the latest epoch value received from the child.
+ // mParentEpoch is the latest epoch value that we have told BrowserParent
+ // about (via ObserveLayerUpdate).
+ LayersObserverEpoch mChildEpoch;
+ LayersObserverEpoch mParentEpoch;
+
+ TimeDuration mVsyncRate;
+
+ struct PendingTransaction {
+ TransactionId mId;
+ VsyncId mTxnVsyncId;
+ TimeStamp mVsyncStartTime;
+ TimeStamp mRefreshStartTime;
+ TimeStamp mTxnStartTime;
+ TimeStamp mTxnEndTime;
+ TimeStamp mFwdTime;
+ nsCString mTxnURL;
+ bool mContainsSVG;
+ };
+ AutoTArray mPendingTransactions;
+
+ // When the widget/frame/browser stuff in this process begins its
+ // destruction process, we need to Disconnect() all the currently
+ // live shadow layers, because some of them might be orphaned from
+ // the layer tree. This happens in Destroy() above. After we
+ // Destroy() ourself, there's a window in which that information
+ // hasn't yet propagated back to the child side and it might still
+ // send us layer transactions. We want to ignore those transactions
+ // because they refer to "zombie layers" on this side. So, we track
+ // that state with |mDestroyed|. This is similar to, but separate
+ // from, |mLayerManager->IsDestroyed()|; we might have had Destroy()
+ // called on us but the mLayerManager might not be destroyed, or
+ // vice versa. In both cases though, we want to ignore shadow-layer
+ // transactions posted by the child.
+
+ bool mDestroyed;
+ bool mIPCOpen;
+
+ // This is set during RecvUpdate to track whether we'll need to update
+ // APZ's hit test regions.
+ bool mUpdateHitTestingTree;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H
diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl
index d58a05658671f..01a8c3a3f3483 100644
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -15,6 +15,7 @@ include protocol PBrowser;
include protocol PCanvas;
include protocol PCompositorManager;
include protocol PCompositorWidget;
+include protocol PLayerTransaction;
include protocol PTexture;
include protocol PWebGL;
include protocol PWebRenderBridge;
@@ -98,6 +99,7 @@ struct FrameStats {
manages PAPZ;
manages PAPZCTreeManager;
// A Compositor manages a single Layer Manager (PLayerTransaction)
+ manages PLayerTransaction;
manages PTexture;
manages PCompositorWidget;
manages PWebRenderBridge;
@@ -207,6 +209,11 @@ parent:
sync StopFrameTimeRecording(uint32_t startIndex)
returns (float[] intervals);
+ // layersBackendHints is an ordered list of preffered backends where
+ // layersBackendHints[0] is the best backend. If any hints are LayersBackend::LAYERS_NONE
+ // that hint is ignored.
+ async PLayerTransaction(LayersBackend[] layersBackendHints, LayersId id);
+
// Notify the compositor that a region of the screen has been invalidated.
async NotifyRegionInvalidated(nsIntRegion region);
diff --git a/gfx/layers/ipc/PLayerTransaction.ipdl b/gfx/layers/ipc/PLayerTransaction.ipdl
new file mode 100644
index 0000000000000..ddc50216e5c38
--- /dev/null
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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/. */
+
+include LayersSurfaces;
+include LayersMessages;
+include protocol PCompositorBridge;
+include protocol PTexture;
+
+include "mozilla/GfxMessageUtils.h";
+include "mozilla/layers/LayersMessageUtils.h";
+
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
+using struct mozilla::void_t from "mozilla/ipc/IPCCore.h";
+using struct mozilla::null_t from "mozilla/ipc/IPCCore.h";
+using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
+using mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
+using mozilla::layers::ScrollableLayerGuid from "mozilla/layers/ScrollableLayerGuid.h";
+using mozilla::layers::ScrollableLayerGuid::ViewID from "mozilla/layers/ScrollableLayerGuid.h";
+using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
+using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::TransactionId from "mozilla/layers/LayersTypes.h";
+
+/**
+ * The layers protocol is spoken between thread contexts that manage
+ * layer (sub)trees. The protocol comprises atomically publishing
+ * layer subtrees to a "shadow" thread context (which grafts the
+ * subtree into its own tree), and atomically updating a published
+ * subtree. ("Atomic" in this sense is wrt painting.)
+ */
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * The PLayerTransaction protocol manages the layer tree for a single "browser".
+ * The "browser" can be a top-level browser window, in which case the PLayer-
+ * TransactionChild exists in the UI process. The "browser" can also be a content
+ * tab, in which case the PLayerTransactionChild exists in the content process.
+ * In either case, the PLayerTransactionParent exists in the GPU process (if
+ * there is one) or the UI process otherwise.
+ */
+sync protocol PLayerTransaction {
+ manager PCompositorBridge;
+
+parent:
+ // The isFirstPaint flag can be used to indicate that this is the first update
+ // for a particular document.
+ async Update(TransactionInfo txn);
+
+ async PaintTime(TransactionId id, TimeDuration paintTime);
+
+ async SetLayersObserverEpoch(LayersObserverEpoch aChildEpoch);
+
+ // Create a new Compositable.
+ async NewCompositable(CompositableHandle handle, TextureInfo info);
+
+ // Release an object that is no longer in use.
+ async ReleaseLayer(LayerHandle layer);
+ async ReleaseCompositable(CompositableHandle compositable);
+
+ // Tell the compositor to notify APZ that a layer has been confirmed for an
+ // input event.
+ async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
+
+ // Testing APIs
+
+ // Enter test mode, set the sample time to sampleTime, and resample
+ // animations. sampleTime must not be null.
+ sync SetTestSampleTime(TimeStamp sampleTime);
+ // Leave test mode and resume normal compositing
+ sync LeaveTestMode();
+
+ // Returns |OMTAValue| applied to the layer.
+ sync GetAnimationValue(uint64_t aCompositorAnimationId) returns (OMTAValue value);
+
+ // Returns the value of the transform applied to the layer by animation and
+ // APZC.
+ sync GetTransform(LayerHandle layer) returns (Matrix4x4? transform);
+
+ // The next time the layer tree is composited, add this async scroll offset in
+ // CSS pixels for the given ViewID.
+ // Useful for testing rendering of async scrolling.
+ sync SetAsyncScrollOffset(ViewID id, float x, float y);
+
+ // The next time the layer tree is composited, include this async zoom in
+ // for the given ViewID.
+ // Useful for testing rendering of async zooming.
+ sync SetAsyncZoom(ViewID id, float zoom);
+
+ // Flush any pending APZ repaints to the main thread.
+ async FlushApzRepaints();
+
+ // Drop any front buffers that might be retained on the compositor
+ // side.
+ async ClearCachedResources();
+
+ // Schedule a composite if one isn't already scheduled.
+ async ScheduleComposite();
+
+ // Get a copy of the compositor-side APZ test data instance for this
+ // layers id.
+ sync GetAPZTestData() returns (APZTestData data);
+
+ // Child requests frame uniformity measurements
+ sync GetFrameUniformity() returns (FrameUniformityData data);
+
+ // Query a named property from the last frame
+ sync RequestProperty(nsString property) returns (float value);
+
+ // Return the TextureFactoryIdentifier for this compositor.
+ sync GetTextureFactoryIdentifier() returns (TextureFactoryIdentifier aIdentifier);
+
+ async RecordPaintTimes(PaintTiming timing);
+
+ async Shutdown();
+ sync ShutdownSync();
+
+child:
+ async __delete__();
+};
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/PTexture.ipdl b/gfx/layers/ipc/PTexture.ipdl
index 18eeb84c897ea..b82a757bbcead 100644
--- a/gfx/layers/ipc/PTexture.ipdl
+++ b/gfx/layers/ipc/PTexture.ipdl
@@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include LayersSurfaces;
+include protocol PLayerTransaction;
include protocol PCompositorBridge;
include protocol PImageBridge;
include protocol PVideoBridge;
diff --git a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
index b095e5c2e9005..891b16e8a2cf8 100644
--- a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
@@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/gfx/Point.h"
+#include "mozilla/layers/PLayerTransaction.h"
+#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/CompositorTypes.h"
@@ -16,6 +18,9 @@ using namespace mozilla::gl;
namespace mozilla {
namespace layers {
+/*static*/
+void ShadowLayerForwarder::PlatformSyncBeforeUpdate() {}
+
/*static*/
void LayerManagerComposite::PlatformSyncBeforeReplyUpdate() {}
diff --git a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
index 24ca1d5ceb4af..25f6ceba21f38 100644
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -24,6 +24,7 @@
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayersMessageUtils.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder, etc
#include "mozilla/mozalloc.h" // for operator new
#include "gfxEnv.h"
#include "nsCOMPtr.h" // for already_AddRefed
@@ -102,6 +103,17 @@ already_AddRefed SurfaceDescriptorX11::OpenForeign() const {
return surf->CairoStatus() ? nullptr : surf.forget();
}
+/*static*/
+void ShadowLayerForwarder::PlatformSyncBeforeUpdate() {
+ if (UsingXCompositing()) {
+ // If we're using X surfaces, then we need to finish all pending
+ // operations on the back buffers before handing them to the
+ // parent, otherwise the surface might be used by the parent's
+ // Display in between two operations queued by our Display.
+ FinishX(DefaultXDisplay());
+ }
+}
+
/*static*/
void LayerManagerComposite::PlatformSyncBeforeReplyUpdate() {
if (UsingXCompositing()) {
diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp
new file mode 100644
index 0000000000000..d149a6d2891bd
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -0,0 +1,972 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "ShadowLayers.h"
+
+#include // for _Rb_tree_const_iterator, etc
+#include // for vector
+
+#include "IPDLActor.h"
+#include "ISurfaceAllocator.h" // for IsSurfaceDescriptorValid
+#include "Layers.h" // for Layer
+#include "RenderTrace.h" // for RenderTraceScope
+#include "gfx2DGlue.h" // for Moz2D transition helpers
+#include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform
+#include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/layers/CompositableClient.h" // for CompositableClient, etc
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/ContentClient.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/LayerTransactionChild.h"
+#include "mozilla/layers/LayersMessages.h" // for Edit, etc
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
+#include "mozilla/layers/PTextureChild.h"
+#include "mozilla/layers/SyncObject.h"
+#ifdef XP_DARWIN
+# include "mozilla/layers/TextureSync.h"
+#endif
+#include "ShadowLayerUtils.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/StaticPrefs_layers.h"
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "nsIXULRuntime.h" // for BrowserTabsRemoteAutostart
+#include "nsTArray.h" // for AutoTArray, nsTArray, etc
+#include "nsTHashSet.h"
+#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+using namespace mozilla::gfx;
+using namespace mozilla::gl;
+using namespace mozilla::ipc;
+
+class ClientTiledLayerBuffer;
+
+typedef nsTArray BufferArray;
+typedef nsTArray EditVector;
+typedef nsTHashSet ShadowableLayerSet;
+typedef nsTArray OpDestroyVector;
+
+class Transaction {
+ public:
+ Transaction()
+ : mTargetRotation(ROTATION_0),
+ mTargetOrientation(hal::eScreenOrientation_None),
+ mOpen(false),
+ mRotationChanged(false) {}
+
+ void Begin(const gfx::IntRect& aTargetBounds, ScreenRotation aRotation,
+ hal::ScreenOrientation aOrientation) {
+ mOpen = true;
+ mTargetBounds = aTargetBounds;
+ if (aRotation != mTargetRotation) {
+ // the first time this is called, mRotationChanged will be false if
+ // aRotation is 0, but we should be OK because for the first transaction
+ // we should only compose if it is non-empty. See the caller(s) of
+ // RotationChanged.
+ mRotationChanged = true;
+ }
+ mTargetRotation = aRotation;
+ mTargetOrientation = aOrientation;
+ }
+ void AddEdit(const Edit& aEdit) {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mCset.AppendElement(aEdit);
+ }
+ void AddEdit(const CompositableOperation& aEdit) { AddEdit(Edit(aEdit)); }
+
+ void AddNoSwapPaint(const CompositableOperation& aPaint) {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mPaints.AppendElement(Edit(aPaint));
+ }
+ void AddMutant(ShadowableLayer* aLayer) {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mMutants.Insert(aLayer);
+ }
+ void AddSimpleMutant(ShadowableLayer* aLayer) {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mSimpleMutants.Insert(aLayer);
+ }
+ void End() {
+ mCset.Clear();
+ mPaints.Clear();
+ mMutants.Clear();
+ mSimpleMutants.Clear();
+ mDestroyedActors.Clear();
+ mOpen = false;
+ mRotationChanged = false;
+ }
+
+ bool Empty() const {
+ return mCset.IsEmpty() && mPaints.IsEmpty() && mMutants.IsEmpty() &&
+ mSimpleMutants.IsEmpty() && mDestroyedActors.IsEmpty();
+ }
+ bool RotationChanged() const { return mRotationChanged; }
+ bool Finished() const { return !mOpen && Empty(); }
+
+ bool Opened() const { return mOpen; }
+
+ EditVector mCset;
+ nsTArray mPaints;
+ OpDestroyVector mDestroyedActors;
+ ShadowableLayerSet mMutants;
+ ShadowableLayerSet mSimpleMutants;
+ gfx::IntRect mTargetBounds;
+ ScreenRotation mTargetRotation;
+ hal::ScreenOrientation mTargetOrientation;
+
+ private:
+ bool mOpen;
+ bool mRotationChanged;
+
+ // disabled
+ Transaction(const Transaction&);
+ Transaction& operator=(const Transaction&);
+};
+struct AutoTxnEnd final {
+ explicit AutoTxnEnd(Transaction* aTxn) : mTxn(aTxn) {}
+ ~AutoTxnEnd() { mTxn->End(); }
+ Transaction* mTxn;
+};
+
+void KnowsCompositor::IdentifyTextureHost(
+ const TextureFactoryIdentifier& aIdentifier) {
+ auto lock = mData.Lock();
+ lock.ref().mTextureFactoryIdentifier = aIdentifier;
+
+ lock.ref().mSyncObject =
+ SyncObjectClient::CreateSyncObjectClientForContentDevice(
+ aIdentifier.mSyncHandle);
+}
+
+KnowsCompositor::KnowsCompositor()
+ : mData("KnowsCompositorMutex"), mSerial(++sSerialCounter) {}
+
+KnowsCompositor::~KnowsCompositor() = default;
+
+KnowsCompositorMediaProxy::KnowsCompositorMediaProxy(
+ const TextureFactoryIdentifier& aIdentifier) {
+ auto lock = mData.Lock();
+ lock.ref().mTextureFactoryIdentifier = aIdentifier;
+ // overwrite mSerial's value set by the parent class because we use the same
+ // serial as the KnowsCompositor we are proxying.
+ mThreadSafeAllocator = ImageBridgeChild::GetSingleton();
+ lock.ref().mSyncObject = mThreadSafeAllocator->GetSyncObject();
+}
+
+KnowsCompositorMediaProxy::~KnowsCompositorMediaProxy() = default;
+
+TextureForwarder* KnowsCompositorMediaProxy::GetTextureForwarder() {
+ return mThreadSafeAllocator->GetTextureForwarder();
+}
+
+LayersIPCActor* KnowsCompositorMediaProxy::GetLayersIPCActor() {
+ return mThreadSafeAllocator->GetLayersIPCActor();
+}
+
+ActiveResourceTracker* KnowsCompositorMediaProxy::GetActiveResourceTracker() {
+ return mThreadSafeAllocator->GetActiveResourceTracker();
+}
+
+void KnowsCompositorMediaProxy::SyncWithCompositor() {
+ mThreadSafeAllocator->SyncWithCompositor();
+}
+
+RefPtr ShadowLayerForwarder::GetForMedia() {
+ return MakeAndAddRef(
+ GetTextureFactoryIdentifier());
+}
+
+ShadowLayerForwarder::ShadowLayerForwarder(
+ ClientLayerManager* aClientLayerManager)
+ : mClientLayerManager(aClientLayerManager),
+ mThread(NS_GetCurrentThread()),
+ mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC),
+ mIsFirstPaint(false),
+ mNextLayerHandle(1) {
+ mTxn = new Transaction();
+ mEventTarget = GetMainThreadSerialEventTarget();
+
+ MOZ_ASSERT(mEventTarget || !XRE_IsContentProcess());
+ mActiveResourceTracker = MakeUnique(
+ 1000, "CompositableForwarder", mEventTarget);
+}
+
+template
+struct ReleaseOnMainThreadTask : public Runnable {
+ UniquePtr mObj;
+
+ explicit ReleaseOnMainThreadTask(UniquePtr& aObj)
+ : Runnable("layers::ReleaseOnMainThreadTask"), mObj(std::move(aObj)) {}
+
+ NS_IMETHOD Run() override {
+ mObj = nullptr;
+ return NS_OK;
+ }
+};
+
+ShadowLayerForwarder::~ShadowLayerForwarder() {
+ MOZ_ASSERT(mTxn->Finished(), "unfinished transaction?");
+ delete mTxn;
+ if (mShadowManager) {
+ mShadowManager->SetForwarder(nullptr);
+ if (NS_IsMainThread()) {
+ mShadowManager->Destroy();
+ } else {
+ if (mEventTarget) {
+ mEventTarget->Dispatch(
+ NewRunnableMethod("LayerTransactionChild::Destroy", mShadowManager,
+ &LayerTransactionChild::Destroy),
+ nsIEventTarget::DISPATCH_NORMAL);
+ } else {
+ NS_DispatchToMainThread(
+ NewRunnableMethod("layers::LayerTransactionChild::Destroy",
+ mShadowManager, &LayerTransactionChild::Destroy));
+ }
+ }
+ }
+
+ if (!NS_IsMainThread()) {
+ RefPtr> event =
+ new ReleaseOnMainThreadTask(
+ mActiveResourceTracker);
+ if (mEventTarget) {
+ mEventTarget->Dispatch(event.forget(), nsIEventTarget::DISPATCH_NORMAL);
+ } else {
+ NS_DispatchToMainThread(event);
+ }
+ }
+}
+
+void ShadowLayerForwarder::BeginTransaction(
+ const gfx::IntRect& aTargetBounds, ScreenRotation aRotation,
+ hal::ScreenOrientation aOrientation) {
+ MOZ_ASSERT(IPCOpen(), "no manager to forward to");
+ MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
+ UpdateFwdTransactionId();
+ mTxn->Begin(aTargetBounds, aRotation, aOrientation);
+}
+
+static const LayerHandle& Shadow(ShadowableLayer* aLayer) {
+ return aLayer->GetShadow();
+}
+
+template
+static void CreatedLayer(Transaction* aTxn, ShadowableLayer* aLayer) {
+ aTxn->AddEdit(OpCreateT(Shadow(aLayer)));
+}
+
+void ShadowLayerForwarder::CreatedPaintedLayer(ShadowableLayer* aThebes) {
+ CreatedLayer(mTxn, aThebes);
+}
+void ShadowLayerForwarder::CreatedContainerLayer(ShadowableLayer* aContainer) {
+ CreatedLayer(mTxn, aContainer);
+}
+void ShadowLayerForwarder::CreatedImageLayer(ShadowableLayer* aImage) {
+ CreatedLayer(mTxn, aImage);
+}
+void ShadowLayerForwarder::CreatedColorLayer(ShadowableLayer* aColor) {
+ CreatedLayer(mTxn, aColor);
+}
+void ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas) {
+ CreatedLayer(mTxn, aCanvas);
+}
+void ShadowLayerForwarder::CreatedRefLayer(ShadowableLayer* aRef) {
+ CreatedLayer(mTxn, aRef);
+}
+
+void ShadowLayerForwarder::Mutated(ShadowableLayer* aMutant) {
+ mTxn->AddMutant(aMutant);
+}
+
+void ShadowLayerForwarder::MutatedSimple(ShadowableLayer* aMutant) {
+ mTxn->AddSimpleMutant(aMutant);
+}
+
+void ShadowLayerForwarder::SetRoot(ShadowableLayer* aRoot) {
+ mTxn->AddEdit(OpSetRoot(Shadow(aRoot)));
+}
+void ShadowLayerForwarder::InsertAfter(ShadowableLayer* aContainer,
+ ShadowableLayer* aChild,
+ ShadowableLayer* aAfter) {
+ if (!aChild->HasShadow()) {
+ return;
+ }
+
+ while (aAfter && !aAfter->HasShadow()) {
+ aAfter = aAfter->AsLayer()->GetPrevSibling()
+ ? aAfter->AsLayer()->GetPrevSibling()->AsShadowableLayer()
+ : nullptr;
+ }
+
+ if (aAfter) {
+ mTxn->AddEdit(
+ OpInsertAfter(Shadow(aContainer), Shadow(aChild), Shadow(aAfter)));
+ } else {
+ mTxn->AddEdit(OpPrependChild(Shadow(aContainer), Shadow(aChild)));
+ }
+}
+void ShadowLayerForwarder::RemoveChild(ShadowableLayer* aContainer,
+ ShadowableLayer* aChild) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] OpRemoveChild container=%p child=%p\n",
+ aContainer->AsLayer(), aChild->AsLayer()));
+
+ if (!aChild->HasShadow()) {
+ return;
+ }
+
+ mTxn->AddEdit(OpRemoveChild(Shadow(aContainer), Shadow(aChild)));
+}
+void ShadowLayerForwarder::RepositionChild(ShadowableLayer* aContainer,
+ ShadowableLayer* aChild,
+ ShadowableLayer* aAfter) {
+ if (!aChild->HasShadow()) {
+ return;
+ }
+
+ while (aAfter && !aAfter->HasShadow()) {
+ aAfter = aAfter->AsLayer()->GetPrevSibling()
+ ? aAfter->AsLayer()->GetPrevSibling()->AsShadowableLayer()
+ : nullptr;
+ }
+
+ if (aAfter) {
+ MOZ_LAYERS_LOG(
+ ("[LayersForwarder] OpRepositionChild container=%p child=%p after=%p",
+ aContainer->AsLayer(), aChild->AsLayer(), aAfter->AsLayer()));
+ mTxn->AddEdit(
+ OpRepositionChild(Shadow(aContainer), Shadow(aChild), Shadow(aAfter)));
+ } else {
+ MOZ_LAYERS_LOG(("[LayersForwarder] OpRaiseToTopChild container=%p child=%p",
+ aContainer->AsLayer(), aChild->AsLayer()));
+ mTxn->AddEdit(OpRaiseToTopChild(Shadow(aContainer), Shadow(aChild)));
+ }
+}
+
+#ifdef DEBUG
+void ShadowLayerForwarder::CheckSurfaceDescriptor(
+ const SurfaceDescriptor* aDescriptor) const {
+ if (!aDescriptor) {
+ return;
+ }
+
+ if (aDescriptor->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer &&
+ aDescriptor->get_SurfaceDescriptorBuffer().data().type() ==
+ MemoryOrShmem::TShmem) {
+ const Shmem& shmem =
+ aDescriptor->get_SurfaceDescriptorBuffer().data().get_Shmem();
+ shmem.AssertInvariants();
+ MOZ_ASSERT(mShadowManager &&
+ mShadowManager->IsTrackingSharedMemory(shmem.mSegment));
+ }
+}
+#endif
+
+void ShadowLayerForwarder::UseTiledLayerBuffer(
+ CompositableClient* aCompositable,
+ const SurfaceDescriptorTiles& aTileLayerDescriptor) {
+ MOZ_ASSERT(aCompositable);
+
+ if (!aCompositable->IsConnected()) {
+ return;
+ }
+
+ mTxn->AddNoSwapPaint(
+ CompositableOperation(aCompositable->GetIPCHandle(),
+ OpUseTiledLayerBuffer(aTileLayerDescriptor)));
+}
+
+void ShadowLayerForwarder::UpdateTextureRegion(
+ CompositableClient* aCompositable,
+ const ThebesBufferData& aThebesBufferData,
+ const nsIntRegion& aUpdatedRegion) {
+ MOZ_ASSERT(aCompositable);
+
+ if (!aCompositable->IsConnected()) {
+ return;
+ }
+
+ mTxn->AddNoSwapPaint(CompositableOperation(
+ aCompositable->GetIPCHandle(),
+ OpPaintTextureRegion(aThebesBufferData, aUpdatedRegion)));
+}
+
+void ShadowLayerForwarder::UseTextures(
+ CompositableClient* aCompositable,
+ const nsTArray& aTextures) {
+ MOZ_ASSERT(aCompositable);
+}
+
+void ShadowLayerForwarder::UseComponentAlphaTextures(
+ CompositableClient* aCompositable, TextureClient* aTextureOnBlack,
+ TextureClient* aTextureOnWhite) {
+ MOZ_ASSERT(aCompositable);
+
+ return;
+}
+
+static bool AddOpDestroy(Transaction* aTxn, const OpDestroy& op) {
+ if (!aTxn->Opened()) {
+ return false;
+ }
+
+ aTxn->mDestroyedActors.AppendElement(op);
+ return true;
+}
+
+bool ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture) {
+ return AddOpDestroy(mTxn, OpDestroy(aTexture));
+}
+
+bool ShadowLayerForwarder::DestroyInTransaction(
+ const CompositableHandle& aHandle) {
+ return AddOpDestroy(mTxn, OpDestroy(aHandle));
+}
+
+void ShadowLayerForwarder::RemoveTextureFromCompositable(
+ CompositableClient* aCompositable, TextureClient* aTexture) {
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(aTexture);
+ MOZ_ASSERT(aTexture->GetIPDLActor());
+ MOZ_RELEASE_ASSERT(aTexture->GetIPDLActor()->GetIPCChannel() ==
+ mShadowManager->GetIPCChannel());
+ if (!aCompositable->IsConnected() || !aTexture->GetIPDLActor()) {
+ // We don't have an actor anymore, don't try to use it!
+ return;
+ }
+
+ mTxn->AddEdit(CompositableOperation(
+ aCompositable->GetIPCHandle(),
+ OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
+}
+
+bool ShadowLayerForwarder::InWorkerThread() {
+ return GetTextureForwarder()->GetThread()->IsOnCurrentThread();
+}
+
+void ShadowLayerForwarder::SendPaintTime(TransactionId aId,
+ TimeDuration aPaintTime) {
+ if (!IPCOpen() || !mShadowManager->SendPaintTime(aId, aPaintTime)) {
+ NS_WARNING("Could not send paint times over IPC");
+ }
+}
+
+bool ShadowLayerForwarder::EndTransaction(
+ const nsIntRegion& aRegionToClear, TransactionId aId,
+ bool aScheduleComposite, uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction, const mozilla::VsyncId& aVsyncId,
+ const mozilla::TimeStamp& aVsyncStart,
+ const mozilla::TimeStamp& aRefreshStart,
+ const mozilla::TimeStamp& aTransactionStart, bool aContainsSVG,
+ const nsCString& aURL, bool* aSent,
+ const nsTArray& aPayload) {
+ *aSent = false;
+
+ TransactionInfo info;
+
+ MOZ_ASSERT(IPCOpen(), "no manager to forward to");
+ if (!IPCOpen()) {
+ return false;
+ }
+
+ Maybe startTime;
+ if (StaticPrefs::layers_acceleration_draw_fps()) {
+ startTime = Some(TimeStamp::Now());
+ }
+
+ GetCompositorBridgeChild()->WillEndTransaction();
+
+ MOZ_ASSERT(aId.IsValid());
+
+ AUTO_PROFILER_LABEL("ShadowLayerForwarder::EndTransaction", GRAPHICS);
+
+ RenderTraceScope rendertrace("Foward Transaction", "000091");
+ MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
+
+ DiagnosticTypes diagnostics =
+ gfxPlatform::GetPlatform()->GetLayerDiagnosticTypes();
+ if (mDiagnosticTypes != diagnostics) {
+ mDiagnosticTypes = diagnostics;
+ mTxn->AddEdit(OpSetDiagnosticTypes(diagnostics));
+ }
+
+ AutoTxnEnd _(mTxn);
+
+ if (mTxn->Empty() && !mTxn->RotationChanged()) {
+ MOZ_LAYERS_LOG(
+ ("[LayersForwarder] 0-length cset (?) and no rotation event, skipping "
+ "Update()"));
+ return true;
+ }
+
+ MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));
+
+ MOZ_LAYERS_LOG(("[LayersForwarder] building transaction..."));
+
+ nsTArray setSimpleAttrs;
+ for (ShadowableLayer* shadow : mTxn->mSimpleMutants) {
+ if (!shadow->HasShadow()) {
+ continue;
+ }
+
+ Layer* mutant = shadow->AsLayer();
+ setSimpleAttrs.AppendElement(OpSetSimpleLayerAttributes(
+ Shadow(shadow), mutant->GetSimpleAttributes()));
+ }
+
+ nsTArray setAttrs;
+
+ // We purposely add attribute-change ops to the final changeset
+ // before we add paint ops. This allows layers to record the
+ // attribute changes before new pixels arrive, which can be useful
+ // for setting up back/front buffers.
+ RenderTraceScope rendertrace2("Foward Transaction", "000092");
+ for (ShadowableLayer* shadow : mTxn->mMutants) {
+ if (!shadow->HasShadow()) {
+ continue;
+ }
+ Layer* mutant = shadow->AsLayer();
+ MOZ_ASSERT(!!mutant, "unshadowable layer?");
+
+ OpSetLayerAttributes op;
+ op.layer() = Shadow(shadow);
+
+ LayerAttributes& attrs = op.attrs();
+ CommonLayerAttributes& common = attrs.common();
+ common.visibleRegion() = mutant->GetVisibleRegion();
+ common.eventRegions() = mutant->GetEventRegions();
+ common.useClipRect() = !!mutant->GetClipRect();
+ common.clipRect() =
+ (common.useClipRect() ? *mutant->GetClipRect() : ParentLayerIntRect());
+ if (Layer* maskLayer = mutant->GetMaskLayer()) {
+ common.maskLayer() = Shadow(maskLayer->AsShadowableLayer());
+ } else {
+ common.maskLayer() = LayerHandle();
+ }
+ common.compositorAnimations().id() = mutant->GetCompositorAnimationsId();
+ common.compositorAnimations().animations() =
+ mutant->GetAnimations().Clone();
+ common.invalidRegion() = mutant->GetInvalidRegion().GetRegion();
+ common.scrollMetadata() = mutant->GetAllScrollMetadata().Clone();
+ for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) {
+ auto layer =
+ Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer());
+ common.ancestorMaskLayers().AppendElement(layer);
+ }
+ nsCString log;
+ mutant->GetDisplayListLog(log);
+ common.displayListLog() = log;
+
+ attrs.specific() = null_t();
+ mutant->FillSpecificAttributes(attrs.specific());
+
+ MOZ_LAYERS_LOG(("[LayersForwarder] OpSetLayerAttributes(%p)\n", mutant));
+
+ setAttrs.AppendElement(op);
+ }
+
+ if (mTxn->mCset.IsEmpty() && mTxn->mPaints.IsEmpty() && setAttrs.IsEmpty() &&
+ !mTxn->RotationChanged()) {
+ return true;
+ }
+
+ info.cset() = std::move(mTxn->mCset);
+ info.setSimpleAttrs() = std::move(setSimpleAttrs);
+ info.setAttrs() = std::move(setAttrs);
+ info.paints() = std::move(mTxn->mPaints);
+ info.toDestroy() = mTxn->mDestroyedActors.Clone();
+ info.fwdTransactionId() = GetFwdTransactionId();
+ info.id() = aId;
+ info.isFirstPaint() = mIsFirstPaint;
+ info.focusTarget() = mFocusTarget;
+ info.scheduleComposite() = aScheduleComposite;
+ info.paintSequenceNumber() = aPaintSequenceNumber;
+ info.isRepeatTransaction() = aIsRepeatTransaction;
+ info.vsyncId() = aVsyncId;
+ info.vsyncStart() = aVsyncStart;
+ info.refreshStart() = aRefreshStart;
+ info.transactionStart() = aTransactionStart;
+ info.url() = aURL;
+ info.containsSVG() = aContainsSVG;
+#if defined(ENABLE_FRAME_LATENCY_LOG)
+ info.fwdTime() = TimeStamp::Now();
+#endif
+ info.payload() = aPayload.Clone();
+
+ TargetConfig targetConfig(mTxn->mTargetBounds, mTxn->mTargetRotation,
+ mTxn->mTargetOrientation, aRegionToClear);
+ info.targetConfig() = targetConfig;
+
+ if (!GetTextureForwarder()->IsSameProcess()) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
+ PlatformSyncBeforeUpdate();
+ }
+
+ if (startTime) {
+ mPaintTiming.serializeMs() =
+ (TimeStamp::Now() - startTime.value()).ToMilliseconds();
+ startTime = Some(TimeStamp::Now());
+ }
+
+ MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
+ RenderTraceScope rendertrace3("Forward Transaction", "000093");
+ if (!mShadowManager->SendUpdate(info)) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
+ return false;
+ }
+
+ if (startTime) {
+ mPaintTiming.sendMs() =
+ (TimeStamp::Now() - startTime.value()).ToMilliseconds();
+ mShadowManager->SendRecordPaintTimes(mPaintTiming);
+ }
+
+ *aSent = true;
+ mIsFirstPaint = false;
+ mFocusTarget = FocusTarget();
+ MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
+ return true;
+}
+
+RefPtr ShadowLayerForwarder::FindCompositable(
+ const CompositableHandle& aHandle) {
+ CompositableClient* client = nullptr;
+ if (!mCompositables.Get(aHandle.Value(), &client)) {
+ return nullptr;
+ }
+ return client;
+}
+
+void ShadowLayerForwarder::SetLayersObserverEpoch(LayersObserverEpoch aEpoch) {
+ if (!IPCOpen()) {
+ return;
+ }
+ Unused << mShadowManager->SendSetLayersObserverEpoch(aEpoch);
+}
+
+void ShadowLayerForwarder::UpdateTextureLocks() {
+#ifdef XP_DARWIN
+ if (!IPCOpen()) {
+ return;
+ }
+
+ auto compositorBridge = GetCompositorBridgeChild();
+ if (compositorBridge) {
+ auto pid = compositorBridge->OtherPid();
+ TextureSync::UpdateTextureLocks(pid);
+ }
+#endif
+}
+
+void ShadowLayerForwarder::SyncTextures(const nsTArray& aSerials) {
+#ifdef XP_DARWIN
+ if (!IPCOpen()) {
+ return;
+ }
+
+ auto compositorBridge = GetCompositorBridgeChild();
+ if (compositorBridge) {
+ auto pid = compositorBridge->OtherPid();
+ TextureSync::WaitForTextures(pid, aSerials);
+ }
+#endif
+}
+
+void ShadowLayerForwarder::ReleaseLayer(const LayerHandle& aHandle) {
+ if (!IPCOpen()) {
+ return;
+ }
+ Unused << mShadowManager->SendReleaseLayer(aHandle);
+}
+
+bool ShadowLayerForwarder::IPCOpen() const {
+ return HasShadowManager() && mShadowManager->IPCOpen();
+}
+
+/**
+ * We bail out when we have no shadow manager. That can happen when the
+ * layer manager is created by the preallocated process.
+ * See bug 914843 for details.
+ */
+LayerHandle ShadowLayerForwarder::ConstructShadowFor(ShadowableLayer* aLayer) {
+ return LayerHandle(mNextLayerHandle++);
+}
+
+#if !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
+
+/*static*/
+void ShadowLayerForwarder::PlatformSyncBeforeUpdate() {}
+
+#endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS)
+
+void ShadowLayerForwarder::Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer) {
+#ifdef GFX_COMPOSITOR_LOGGING
+ printf("ShadowLayerForwarder::Connect(Compositable)\n");
+#endif
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(mShadowManager);
+ if (!IPCOpen()) {
+ return;
+ }
+
+ static uint64_t sNextID = 1;
+ uint64_t id = sNextID++;
+
+ mCompositables.InsertOrUpdate(id, aCompositable);
+
+ CompositableHandle handle(id);
+ aCompositable->InitIPDL(handle);
+ mShadowManager->SendNewCompositable(handle, aCompositable->GetTextureInfo());
+}
+
+void ShadowLayerForwarder::Attach(CompositableClient* aCompositable,
+ ShadowableLayer* aLayer) {
+ MOZ_ASSERT(aLayer);
+ MOZ_ASSERT(aCompositable);
+ mTxn->AddEdit(
+ OpAttachCompositable(Shadow(aLayer), aCompositable->GetIPCHandle()));
+}
+
+void ShadowLayerForwarder::AttachAsyncCompositable(
+ const CompositableHandle& aHandle, ShadowableLayer* aLayer) {
+ MOZ_ASSERT(aLayer);
+ MOZ_ASSERT(aHandle);
+ mTxn->AddEdit(OpAttachAsyncCompositable(Shadow(aLayer), aHandle));
+}
+
+void ShadowLayerForwarder::SetShadowManager(
+ PLayerTransactionChild* aShadowManager) {
+ mShadowManager = static_cast(aShadowManager);
+ mShadowManager->SetForwarder(this);
+}
+
+void ShadowLayerForwarder::StopReceiveAsyncParentMessge() {
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SetForwarder(nullptr);
+}
+
+void ShadowLayerForwarder::ClearCachedResources() {
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SendClearCachedResources();
+}
+
+void ShadowLayerForwarder::ScheduleComposite() {
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SendScheduleComposite();
+}
+
+bool IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface) {
+ return aSurface.type() != SurfaceDescriptor::T__None &&
+ aSurface.type() != SurfaceDescriptor::Tnull_t;
+}
+
+uint8_t* GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor) {
+ MOZ_ASSERT(IsSurfaceDescriptorValid(aDescriptor));
+ MOZ_RELEASE_ASSERT(
+ aDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer,
+ "GFX: surface descriptor is not the right type.");
+
+ auto memOrShmem = aDescriptor.get_SurfaceDescriptorBuffer().data();
+ if (memOrShmem.type() == MemoryOrShmem::TShmem) {
+ return memOrShmem.get_Shmem().get();
+ } else {
+ return reinterpret_cast(memOrShmem.get_uintptr_t());
+ }
+}
+
+already_AddRefed GetSurfaceForDescriptor(
+ const SurfaceDescriptor& aDescriptor) {
+ if (aDescriptor.type() != SurfaceDescriptor::TSurfaceDescriptorBuffer) {
+ return nullptr;
+ }
+ uint8_t* data = GetAddressFromDescriptor(aDescriptor);
+ auto rgb =
+ aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
+ uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
+ return gfx::Factory::CreateWrappingDataSourceSurface(data, stride, rgb.size(),
+ rgb.format());
+}
+
+already_AddRefed GetDrawTargetForDescriptor(
+ const SurfaceDescriptor& aDescriptor) {
+ uint8_t* data = GetAddressFromDescriptor(aDescriptor);
+ auto rgb =
+ aDescriptor.get_SurfaceDescriptorBuffer().desc().get_RGBDescriptor();
+ uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
+ return gfx::Factory::CreateDrawTargetForData(
+ gfx::BackendType::SKIA, data, rgb.size(), stride, rgb.format());
+}
+
+void DestroySurfaceDescriptor(IShmemAllocator* aAllocator,
+ SurfaceDescriptor* aSurface) {
+ MOZ_ASSERT(aSurface);
+
+ SurfaceDescriptorBuffer& desc = aSurface->get_SurfaceDescriptorBuffer();
+ switch (desc.data().type()) {
+ case MemoryOrShmem::TShmem: {
+ aAllocator->DeallocShmem(desc.data().get_Shmem());
+ break;
+ }
+ case MemoryOrShmem::Tuintptr_t: {
+ uint8_t* ptr = (uint8_t*)desc.data().get_uintptr_t();
+ GfxMemoryImageReporter::WillFree(ptr);
+ delete[] ptr;
+ break;
+ }
+ default:
+ MOZ_CRASH("surface type not implemented!");
+ }
+ *aSurface = SurfaceDescriptor();
+}
+
+bool ShadowLayerForwarder::AllocSurfaceDescriptor(const gfx::IntSize& aSize,
+ gfxContentType aContent,
+ SurfaceDescriptor* aBuffer) {
+ if (!IPCOpen()) {
+ return false;
+ }
+ return AllocSurfaceDescriptorWithCaps(aSize, aContent, DEFAULT_BUFFER_CAPS,
+ aBuffer);
+}
+
+bool ShadowLayerForwarder::AllocSurfaceDescriptorWithCaps(
+ const gfx::IntSize& aSize, gfxContentType aContent, uint32_t aCaps,
+ SurfaceDescriptor* aBuffer) {
+ if (!IPCOpen()) {
+ return false;
+ }
+ gfx::SurfaceFormat format =
+ gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aContent);
+ size_t size = ImageDataSerializer::ComputeRGBBufferSize(aSize, format);
+ if (!size) {
+ return false;
+ }
+
+ MemoryOrShmem bufferDesc;
+ if (GetTextureForwarder()->IsSameProcess()) {
+ uint8_t* data = new (std::nothrow) uint8_t[size];
+ if (!data) {
+ return false;
+ }
+ GfxMemoryImageReporter::DidAlloc(data);
+ memset(data, 0, size);
+ bufferDesc = reinterpret_cast(data);
+ } else {
+ mozilla::ipc::Shmem shmem;
+ if (!GetTextureForwarder()->AllocUnsafeShmem(size, OptimalShmemType(),
+ &shmem)) {
+ return false;
+ }
+
+ bufferDesc = std::move(shmem);
+ }
+
+ // Use an intermediate buffer by default. Skipping the intermediate buffer is
+ // only possible in certain configurations so let's keep it simple here for
+ // now.
+ const bool hasIntermediateBuffer = true;
+ *aBuffer = SurfaceDescriptorBuffer(
+ RGBDescriptor(aSize, format, hasIntermediateBuffer), bufferDesc);
+
+ return true;
+}
+
+/* static */
+bool ShadowLayerForwarder::IsShmem(SurfaceDescriptor* aSurface) {
+ return aSurface &&
+ (aSurface->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer) &&
+ (aSurface->get_SurfaceDescriptorBuffer().data().type() ==
+ MemoryOrShmem::TShmem);
+}
+
+void ShadowLayerForwarder::DestroySurfaceDescriptor(
+ SurfaceDescriptor* aSurface) {
+ MOZ_ASSERT(aSurface);
+ MOZ_ASSERT(IPCOpen());
+ if (!IPCOpen() || !aSurface) {
+ return;
+ }
+
+ ::mozilla::layers::DestroySurfaceDescriptor(GetTextureForwarder(), aSurface);
+}
+
+void ShadowLayerForwarder::UpdateFwdTransactionId() {
+ auto compositorBridge = GetCompositorBridgeChild();
+ if (compositorBridge) {
+ compositorBridge->UpdateFwdTransactionId();
+ }
+}
+
+uint64_t ShadowLayerForwarder::GetFwdTransactionId() {
+ auto compositorBridge = GetCompositorBridgeChild();
+ MOZ_DIAGNOSTIC_ASSERT(compositorBridge);
+ return compositorBridge ? compositorBridge->GetFwdTransactionId() : 0;
+}
+
+CompositorBridgeChild* ShadowLayerForwarder::GetCompositorBridgeChild() {
+ if (mCompositorBridgeChild) {
+ return mCompositorBridgeChild;
+ }
+ if (!mShadowManager) {
+ return nullptr;
+ }
+ mCompositorBridgeChild =
+ static_cast(mShadowManager->Manager());
+ return mCompositorBridgeChild;
+}
+
+void ShadowLayerForwarder::SyncWithCompositor() {
+ auto compositorBridge = GetCompositorBridgeChild();
+ if (compositorBridge && compositorBridge->IPCOpen()) {
+ compositorBridge->SendSyncWithCompositor();
+ }
+}
+
+void ShadowLayerForwarder::ReleaseCompositable(
+ const CompositableHandle& aHandle) {
+ AssertInForwarderThread();
+ if (!DestroyInTransaction(aHandle)) {
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SendReleaseCompositable(aHandle);
+ }
+ mCompositables.Remove(aHandle.Value());
+}
+
+void ShadowLayerForwarder::SynchronouslyShutdown() {
+ if (IPCOpen()) {
+ mShadowManager->SendShutdownSync();
+ mShadowManager->MarkDestroyed();
+ }
+}
+
+ShadowableLayer::~ShadowableLayer() {
+ if (mShadow) {
+ mForwarder->ReleaseLayer(GetShadow());
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h
new file mode 100644
index 0000000000000..d3b29d7c1ec08
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -0,0 +1,473 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_ShadowLayers_h
+#define mozilla_layers_ShadowLayers_h 1
+
+#include // for size_t
+#include // for uint64_t
+#include "gfxTypes.h"
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/WidgetUtils.h" // for ScreenRotation
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/HalScreenConfiguration.h" // for ScreenOrientation
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/FocusTarget.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/TextureForwarder.h"
+#include "mozilla/layers/CompositorTypes.h" // for OpenMode, etc
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsRegion.h" // for nsIntRegion
+#include "nsTArrayForwardDeclare.h" // for nsTArray
+#include "nsTHashMap.h"
+#include "nsIWidget.h"
+#include
+
+namespace mozilla {
+namespace layers {
+
+class ClientLayerManager;
+class CompositorBridgeChild;
+class FixedSizeSmallShmemSectionAllocator;
+class ImageContainer;
+class Layer;
+class PLayerTransactionChild;
+class LayerTransactionChild;
+class ShadowableLayer;
+class SurfaceDescriptor;
+class TextureClient;
+class ThebesBuffer;
+class ThebesBufferData;
+class Transaction;
+
+/**
+ * We want to share layer trees across thread contexts and address
+ * spaces for several reasons; chief among them
+ *
+ * - a parent process can paint a child process's layer tree while
+ * the child process is blocked, say on content script. This is
+ * important on mobile devices where UI responsiveness is key.
+ *
+ * - a dedicated "compositor" process can asynchronously (wrt the
+ * browser process) composite and animate layer trees, allowing a
+ * form of pipeline parallelism between compositor/browser/content
+ *
+ * - a dedicated "compositor" process can take all responsibility for
+ * accessing the GPU, which is desirable on systems with
+ * buggy/leaky drivers because the compositor process can die while
+ * browser and content live on (and failover mechanisms can be
+ * installed to quickly bring up a replacement compositor)
+ *
+ * The Layers model has a crisply defined API, which makes it easy to
+ * safely "share" layer trees. The ShadowLayers API extends Layers to
+ * allow a remote, parent process to access a child process's layer
+ * tree.
+ *
+ * ShadowLayerForwarder publishes a child context's layer tree to a
+ * parent context. This comprises recording layer-tree modifications
+ * into atomic transactions and pushing them over IPC.
+ *
+ * LayerManagerComposite grafts layer subtrees published by child-context
+ * ShadowLayerForwarder(s) into a parent-context layer tree.
+ *
+ * (Advanced note: because our process tree may have a height >2, a
+ * non-leaf subprocess may both receive updates from child processes
+ * and publish them to parent processes. Put another way,
+ * LayerManagers may be both LayerManagerComposites and
+ * ShadowLayerForwarders.)
+ *
+ * There are only shadow types for layers that have different shadow
+ * vs. not-shadow behavior. ColorLayers and ContainerLayers behave
+ * the same way in both regimes (so far).
+ *
+ *
+ * The mecanism to shadow the layer tree on the compositor through IPC works as
+ * follows:
+ * The layer tree is managed on the content thread, and shadowed in the
+ * compositor thread. The shadow layer tree is only kept in sync with whatever
+ * happens in the content thread. To do this we use IPDL protocols. IPDL is a
+ * domain specific language that describes how two processes or thread should
+ * communicate. C++ code is generated from .ipdl files to implement the message
+ * passing, synchronization and serialization logic. To use the generated code
+ * we implement classes that inherit the generated IPDL actor. the ipdl actors
+ * of a protocol PX are PXChild or PXParent (the generated class), and we
+ * conventionally implement XChild and XParent. The Parent side of the protocol
+ * is the one that lives on the compositor thread. Think of IPDL actors as
+ * endpoints of communication. they are useful to send messages and also to
+ * dispatch the message to the right actor on the other side. One nice property
+ * of an IPDL actor is that when an actor, say PXChild is sent in a message, the
+ * PXParent comes out in the other side. we use this property a lot to dispatch
+ * messages to the right layers and compositable, each of which have their own
+ * ipdl actor on both side.
+ *
+ * Most of the synchronization logic happens in layer transactions and
+ * compositable transactions.
+ * A transaction is a set of changes to the layers and/or the compositables
+ * that are sent and applied together to the compositor thread to keep the
+ * LayerComposite in a coherent state.
+ * Layer transactions maintain the shape of the shadow layer tree, and
+ * synchronize the texture data held by compositables. Layer transactions
+ * are always between the content thread and the compositor thread.
+ * Compositable transactions are subset of a layer transaction with which only
+ * compositables and textures can be manipulated, and does not always originate
+ * from the content thread. (See CompositableForwarder.h and ImageBridgeChild.h)
+ */
+
+class ShadowLayerForwarder final : public LayersIPCActor,
+ public CompositableForwarder,
+ public LegacySurfaceDescriptorAllocator {
+ friend class ClientLayerManager;
+
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ShadowLayerForwarder, override);
+
+ /**
+ * Setup the IPDL actor for aCompositable to be part of layers
+ * transactions.
+ */
+ void Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer) override;
+
+ /**
+ * Adds an edit in the layers transaction in order to attach
+ * the corresponding compositable and layer on the compositor side.
+ * Connect must have been called on aCompositable beforehand.
+ */
+ void Attach(CompositableClient* aCompositable, ShadowableLayer* aLayer);
+
+ /**
+ * Adds an edit in the transaction in order to attach a Compositable that
+ * is not managed by this ShadowLayerForwarder (for example, by ImageBridge
+ * in the case of async-video).
+ * Since the compositable is not managed by this forwarder, we can't use
+ * the compositable or it's IPDL actor here, so we use an ID instead, that
+ * is matched on the compositor side.
+ */
+ void AttachAsyncCompositable(const CompositableHandle& aHandle,
+ ShadowableLayer* aLayer);
+
+ /**
+ * Begin recording a transaction to be forwarded atomically to a
+ * LayerManagerComposite.
+ */
+ void BeginTransaction(const gfx::IntRect& aTargetBounds,
+ ScreenRotation aRotation,
+ hal::ScreenOrientation aOrientation);
+
+ /**
+ * The following methods may only be called after BeginTransaction()
+ * but before EndTransaction(). They mirror the LayerManager
+ * interface in Layers.h.
+ */
+
+ /**
+ * Notify the shadow manager that a new, "real" layer has been
+ * created, and a corresponding shadow layer should be created in
+ * the compositing process.
+ */
+ void CreatedPaintedLayer(ShadowableLayer* aThebes);
+ void CreatedContainerLayer(ShadowableLayer* aContainer);
+ void CreatedImageLayer(ShadowableLayer* aImage);
+ void CreatedColorLayer(ShadowableLayer* aColor);
+ void CreatedCanvasLayer(ShadowableLayer* aCanvas);
+ void CreatedRefLayer(ShadowableLayer* aRef);
+
+ /**
+ * At least one attribute of |aMutant| has changed, and |aMutant|
+ * needs to sync to its shadow layer. This initial implementation
+ * forwards all attributes when any of the appropriate attribute
+ * set is mutated.
+ */
+ void Mutated(ShadowableLayer* aMutant);
+ void MutatedSimple(ShadowableLayer* aMutant);
+
+ void SetRoot(ShadowableLayer* aRoot);
+ /**
+ * Insert |aChild| after |aAfter| in |aContainer|. |aAfter| can be
+ * nullptr to indicated that |aChild| should be appended to the end of
+ * |aContainer|'s child list.
+ */
+ void InsertAfter(ShadowableLayer* aContainer, ShadowableLayer* aChild,
+ ShadowableLayer* aAfter = nullptr);
+ void RemoveChild(ShadowableLayer* aContainer, ShadowableLayer* aChild);
+ void RepositionChild(ShadowableLayer* aContainer, ShadowableLayer* aChild,
+ ShadowableLayer* aAfter = nullptr);
+
+ /**
+ * Set aMaskLayer as the mask on aLayer.
+ * Note that only image layers are properly supported
+ * LayerTransactionParent::UpdateMask and accompanying ipdl
+ * will need changing to update properties for other kinds
+ * of mask layer.
+ */
+ void SetMask(ShadowableLayer* aLayer, ShadowableLayer* aMaskLayer);
+
+ /**
+ * See CompositableForwarder::UseTiledLayerBuffer
+ */
+ void UseTiledLayerBuffer(
+ CompositableClient* aCompositable,
+ const SurfaceDescriptorTiles& aTileLayerDescriptor) override;
+
+ void ReleaseCompositable(const CompositableHandle& aHandle) override;
+ bool DestroyInTransaction(PTextureChild* aTexture) override;
+ bool DestroyInTransaction(const CompositableHandle& aHandle);
+
+ void RemoveTextureFromCompositable(CompositableClient* aCompositable,
+ TextureClient* aTexture) override;
+
+ /**
+ * Communicate to the compositor that aRegion in the texture identified by
+ * aLayer and aIdentifier has been updated to aThebesBuffer.
+ */
+ void UpdateTextureRegion(CompositableClient* aCompositable,
+ const ThebesBufferData& aThebesBufferData,
+ const nsIntRegion& aUpdatedRegion) override;
+
+ /**
+ * See CompositableForwarder::UseTextures
+ */
+ void UseTextures(CompositableClient* aCompositable,
+ const nsTArray& aTextures) override;
+ void UseComponentAlphaTextures(CompositableClient* aCompositable,
+ TextureClient* aClientOnBlack,
+ TextureClient* aClientOnWhite) override;
+
+ /**
+ * Used for debugging to tell the compositor how long this frame took to
+ * paint.
+ */
+ void SendPaintTime(TransactionId aId, TimeDuration aPaintTime);
+
+ /**
+ * End the current transaction and forward it to LayerManagerComposite.
+ * |aReplies| are directions from the LayerManagerComposite to the
+ * caller of EndTransaction().
+ */
+ bool EndTransaction(const nsIntRegion& aRegionToClear, TransactionId aId,
+ bool aScheduleComposite, uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ const mozilla::VsyncId& aVsyncId,
+ const mozilla::TimeStamp& aVsyncTime,
+ const mozilla::TimeStamp& aRefreshStart,
+ const mozilla::TimeStamp& aTransactionStart,
+ bool aContainsSVG, const nsCString& aURL, bool* aSent,
+ const nsTArray& aPayload =
+ nsTArray());
+
+ /**
+ * Set an actor through which layer updates will be pushed.
+ */
+ void SetShadowManager(PLayerTransactionChild* aShadowManager);
+
+ void StopReceiveAsyncParentMessge();
+
+ void ClearCachedResources();
+
+ void ScheduleComposite();
+
+ /**
+ * True if this is forwarding to a LayerManagerComposite.
+ */
+ bool HasShadowManager() const { return !!mShadowManager; }
+ LayerTransactionChild* GetShadowManager() const {
+ return mShadowManager.get();
+ }
+
+ // Send a synchronous message asking the LayerTransactionParent in the
+ // compositor to shutdown.
+ void SynchronouslyShutdown();
+
+ /**
+ * The following Alloc/Open/Destroy interfaces abstract over the
+ * details of working with surfaces that are shared across
+ * processes. They provide the glue between C++ Layers and the
+ * LayerComposite IPC system.
+ *
+ * The basic lifecycle is
+ *
+ * - a Layer needs a buffer. Its ShadowableLayer subclass calls
+ * AllocBuffer(), then calls one of the Created*Buffer() methods
+ * above to transfer the (temporary) front buffer to its
+ * LayerComposite in the other process. The Layer needs a
+ * gfxASurface to paint, so the ShadowableLayer uses
+ * OpenDescriptor(backBuffer) to get that surface, and hands it
+ * out to the Layer.
+ *
+ * - a Layer has painted new pixels. Its ShadowableLayer calls one
+ * of the Painted*Buffer() methods above with the back buffer
+ * descriptor. This notification is forwarded to the LayerComposite,
+ * which uses OpenDescriptor() to access the newly-painted pixels.
+ * The LayerComposite then updates its front buffer in a Layer- and
+ * platform-dependent way, and sends a surface descriptor back to
+ * the ShadowableLayer that becomes its new back back buffer.
+ *
+ * - a Layer wants to destroy its buffers. Its ShadowableLayer
+ * calls Destroyed*Buffer(), which gives up control of the back
+ * buffer descriptor. The actual back buffer surface is then
+ * destroyed using DestroySharedSurface() just before notifying
+ * the parent process. When the parent process is notified, the
+ * LayerComposite also calls DestroySharedSurface() on its front
+ * buffer, and the double-buffer pair is gone.
+ */
+
+ bool IPCOpen() const override;
+
+ /**
+ * Construct a shadow of |aLayer| on the "other side", at the
+ * LayerManagerComposite.
+ */
+ LayerHandle ConstructShadowFor(ShadowableLayer* aLayer);
+
+ /**
+ * Flag the next paint as the first for a document.
+ */
+ void SetIsFirstPaint() { mIsFirstPaint = true; }
+ bool GetIsFirstPaint() const { return mIsFirstPaint; }
+
+ /**
+ * Set the current focus target to be sent with the next paint.
+ */
+ void SetFocusTarget(const FocusTarget& aFocusTarget) {
+ mFocusTarget = aFocusTarget;
+ }
+
+ void SetLayersObserverEpoch(LayersObserverEpoch aEpoch);
+
+ static void PlatformSyncBeforeUpdate();
+
+ bool AllocSurfaceDescriptor(const gfx::IntSize& aSize,
+ gfxContentType aContent,
+ SurfaceDescriptor* aBuffer) override;
+
+ bool AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
+ gfxContentType aContent, uint32_t aCaps,
+ SurfaceDescriptor* aBuffer) override;
+
+ void DestroySurfaceDescriptor(SurfaceDescriptor* aSurface) override;
+
+ void UpdateFwdTransactionId() override;
+ uint64_t GetFwdTransactionId() override;
+
+ void UpdateTextureLocks();
+ void SyncTextures(const nsTArray& aSerials);
+
+ void ReleaseLayer(const LayerHandle& aHandle);
+
+ bool InForwarderThread() override { return NS_IsMainThread(); }
+
+ PaintTiming& GetPaintTiming() { return mPaintTiming; }
+
+ ShadowLayerForwarder* AsLayerForwarder() override { return this; }
+
+ // Returns true if aSurface wraps a Shmem.
+ static bool IsShmem(SurfaceDescriptor* aSurface);
+
+ void SyncWithCompositor() override;
+
+ TextureForwarder* GetTextureForwarder() override {
+ return GetCompositorBridgeChild();
+ }
+ LayersIPCActor* GetLayersIPCActor() override { return this; }
+
+ ActiveResourceTracker* GetActiveResourceTracker() override {
+ return mActiveResourceTracker.get();
+ }
+
+ CompositorBridgeChild* GetCompositorBridgeChild();
+
+ nsISerialEventTarget* GetEventTarget() { return mEventTarget; };
+
+ bool IsThreadSafe() const override { return false; }
+
+ RefPtr GetForMedia() override;
+
+ protected:
+ virtual ~ShadowLayerForwarder();
+
+ explicit ShadowLayerForwarder(ClientLayerManager* aClientLayerManager);
+
+#ifdef DEBUG
+ void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const;
+#else
+ void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const {}
+#endif
+
+ RefPtr FindCompositable(
+ const CompositableHandle& aHandle);
+
+ bool InWorkerThread();
+
+ RefPtr mShadowManager;
+ RefPtr mCompositorBridgeChild;
+
+ private:
+ ClientLayerManager* mClientLayerManager;
+ Transaction* mTxn;
+ nsCOMPtr mThread;
+ DiagnosticTypes mDiagnosticTypes;
+ bool mIsFirstPaint;
+ FocusTarget mFocusTarget;
+ UniquePtr mActiveResourceTracker;
+ uint64_t mNextLayerHandle;
+ nsTHashMap mCompositables;
+ PaintTiming mPaintTiming;
+ /**
+ * ShadowLayerForwarder might dispatch tasks to main while puppet widget and
+ * browserChild don't exist anymore; therefore we hold the event target since
+ * its lifecycle is independent of these objects.
+ */
+ nsCOMPtr mEventTarget;
+};
+
+class CompositableClient;
+
+/**
+ * A ShadowableLayer is a Layer can be shared with a parent context
+ * through a ShadowLayerForwarder. A ShadowableLayer maps to a
+ * Shadow*Layer in a parent context.
+ *
+ * Note that ShadowLayers can themselves be ShadowableLayers.
+ */
+class ShadowableLayer {
+ public:
+ virtual ~ShadowableLayer();
+
+ virtual Layer* AsLayer() = 0;
+
+ /**
+ * True if this layer has a shadow in a parent process.
+ */
+ bool HasShadow() { return mShadow.IsValid(); }
+
+ /**
+ * Return the IPC handle to a Shadow*Layer referring to this if one
+ * exists, nullptr if not.
+ */
+ const LayerHandle& GetShadow() { return mShadow; }
+
+ void SetShadow(ShadowLayerForwarder* aForwarder, const LayerHandle& aShadow) {
+ MOZ_ASSERT(!mShadow, "can't have two shadows (yet)");
+ mForwarder = aForwarder;
+ mShadow = aShadow;
+ }
+
+ virtual CompositableClient* GetCompositableClient() { return nullptr; }
+
+ protected:
+ ShadowableLayer() = default;
+
+ private:
+ RefPtr mForwarder;
+ LayerHandle mShadow;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_ShadowLayers_h
diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build
index 5656597ae801d..33501fbc768b6 100755
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -186,9 +186,12 @@ EXPORTS.mozilla.layers += [
"ipc/KnowsCompositor.h",
"ipc/LayerAnimationUtils.h",
"ipc/LayersMessageUtils.h",
+ "ipc/LayerTransactionChild.h",
+ "ipc/LayerTransactionParent.h",
"ipc/LayerTreeOwnerTracker.h",
"ipc/RefCountedShmem.h",
"ipc/RemoteContentController.h",
+ "ipc/ShadowLayers.h",
"ipc/SharedPlanarYCbCrImage.h",
"ipc/SharedRGBImage.h",
"ipc/SharedSurfacesChild.h",
@@ -439,11 +442,13 @@ UNIFIED_SOURCES += [
"ipc/ImageBridgeChild.cpp",
"ipc/ImageBridgeParent.cpp",
"ipc/ISurfaceAllocator.cpp",
- "ipc/KnowsCompositor.cpp",
"ipc/LayerAnimationUtils.cpp",
+ "ipc/LayerTransactionChild.cpp",
+ "ipc/LayerTransactionParent.cpp",
"ipc/LayerTreeOwnerTracker.cpp",
"ipc/RefCountedShmem.cpp",
"ipc/RemoteContentController.cpp",
+ "ipc/ShadowLayers.cpp",
"ipc/SharedPlanarYCbCrImage.cpp",
"ipc/SharedRGBImage.cpp",
"ipc/SharedSurfacesChild.cpp",
@@ -533,6 +538,7 @@ IPDL_SOURCES += [
"ipc/PCompositorBridgeTypes.ipdlh",
"ipc/PCompositorManager.ipdl",
"ipc/PImageBridge.ipdl",
+ "ipc/PLayerTransaction.ipdl",
"ipc/PTexture.ipdl",
"ipc/PUiCompositorController.ipdl",
"ipc/PVideoBridge.ipdl",
diff --git a/ipc/ipdl/message-metadata.ini b/ipc/ipdl/message-metadata.ini
index 50ad642537962..88c471502626d 100644
--- a/ipc/ipdl/message-metadata.ini
+++ b/ipc/ipdl/message-metadata.ini
@@ -8,6 +8,8 @@
segment_capacity = 16384
[PContent::AccumulateChildHistograms]
segment_capacity = 16384
+[PLayerTransaction::Update]
+segment_capacity = 8192
[PContent::StoreAndBroadcastBlobURLRegistration]
segment_capacity = 8192
[PHttpChannel::Redirect1Begin]
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index 662a33d09b904..c55d6131f8c58 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -85,6 +85,7 @@
#include "mozilla/layers/APZPublicUtils.h"
#include "mozilla/layers/AxisPhysicsModel.h"
#include "mozilla/layers/AxisPhysicsMSDModel.h"
+#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/ScrollLinkedEffectDetector.h"
#include "mozilla/Unused.h"
#include "MobileViewportManager.h"
diff --git a/layout/ipc/RemoteLayerTreeOwner.cpp b/layout/ipc/RemoteLayerTreeOwner.cpp
index f860921f50cea..feb442cb1cbb2 100644
--- a/layout/ipc/RemoteLayerTreeOwner.cpp
+++ b/layout/ipc/RemoteLayerTreeOwner.cpp
@@ -11,6 +11,7 @@
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/LayerTransactionParent.h"
#include "nsFrameLoader.h"
#include "nsStyleStructInlines.h"
#include "nsSubDocumentFrame.h"
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
index cfe04b1ff9721..0c1216dc19385 100644
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -27,6 +27,7 @@
#include "mozilla/dom/SVGElement.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/PLayerTransaction.h"
#include "mozilla/PresShell.h"
#include "mozilla/ShapeUtils.h"
#include "mozilla/StaticPrefs_apz.h"
diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp
index 4be2be01055c3..05227999749dd 100644
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -14,6 +14,7 @@
#include "mozilla/Hal.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/layers/APZChild.h"
+#include "mozilla/layers/PLayerTransactionChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp
index 430e8e890f18d..a8032e851ea5c 100644
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -123,6 +123,7 @@ using mozilla::java::GeckoSession;
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/CompositorSession.h"
+#include "mozilla/layers/LayerTransactionParent.h"
#include "mozilla/layers/UiCompositorControllerChild.h"
#include "nsThreadUtils.h"
diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp
index 1c1d468a60d0a..8598fe46e9a3f 100644
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -52,6 +52,7 @@
#include "mozilla/layers/IAPZCTreeManager.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/InputAPZContext.h"
+#include "mozilla/layers/PLayerTransactionChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "nsAppDirectoryServiceDefs.h"
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
index 51bb037316629..fbe9c390277e7 100644
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -81,6 +81,7 @@ class CompositorBridgeChild;
struct FrameMetrics;
class LayerManager;
class LayerManagerComposite;
+class PLayerTransactionChild;
class WebRenderBridgeChild;
} // namespace layers
namespace gfx {
@@ -380,6 +381,7 @@ class nsIWidget : public nsISupports {
typedef mozilla::layers::LayerManagerComposite LayerManagerComposite;
typedef mozilla::layers::LayersBackend LayersBackend;
typedef mozilla::layers::LayersId LayersId;
+ typedef mozilla::layers::PLayerTransactionChild PLayerTransactionChild;
typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
typedef mozilla::layers::ZoomConstraints ZoomConstraints;
typedef mozilla::widget::IMEEnabled IMEEnabled;