summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/ipc')
-rw-r--r--gfx/layers/ipc/APZCTreeManagerChild.cpp266
-rw-r--r--gfx/layers/ipc/APZCTreeManagerChild.h111
-rw-r--r--gfx/layers/ipc/APZCTreeManagerParent.cpp313
-rw-r--r--gfx/layers/ipc/APZCTreeManagerParent.h151
-rw-r--r--gfx/layers/ipc/APZChild.cpp98
-rw-r--r--gfx/layers/ipc/APZChild.h55
-rw-r--r--gfx/layers/ipc/CompositableForwarder.cpp28
-rw-r--r--gfx/layers/ipc/CompositableForwarder.h127
-rw-r--r--gfx/layers/ipc/CompositableTransactionParent.cpp245
-rw-r--r--gfx/layers/ipc/CompositableTransactionParent.h55
-rw-r--r--gfx/layers/ipc/CompositorBench.cpp345
-rw-r--r--gfx/layers/ipc/CompositorBench.h31
-rw-r--r--gfx/layers/ipc/CompositorBridgeChild.cpp1150
-rw-r--r--gfx/layers/ipc/CompositorBridgeChild.h333
-rw-r--r--gfx/layers/ipc/CompositorBridgeParent.cpp2441
-rw-r--r--gfx/layers/ipc/CompositorBridgeParent.h688
-rw-r--r--gfx/layers/ipc/CompositorThread.cpp155
-rw-r--r--gfx/layers/ipc/CompositorThread.h68
-rw-r--r--gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp578
-rw-r--r--gfx/layers/ipc/CrossProcessCompositorBridgeParent.h177
-rw-r--r--gfx/layers/ipc/GonkNativeHandle.cpp80
-rw-r--r--gfx/layers/ipc/GonkNativeHandle.h24
-rw-r--r--gfx/layers/ipc/GonkNativeHandleUtils.cpp93
-rw-r--r--gfx/layers/ipc/GonkNativeHandleUtils.h26
-rw-r--r--gfx/layers/ipc/ISurfaceAllocator.cpp235
-rw-r--r--gfx/layers/ipc/ISurfaceAllocator.h318
-rw-r--r--gfx/layers/ipc/ImageBridgeChild.cpp1239
-rw-r--r--gfx/layers/ipc/ImageBridgeChild.h400
-rw-r--r--gfx/layers/ipc/ImageBridgeParent.cpp449
-rw-r--r--gfx/layers/ipc/ImageBridgeParent.h155
-rw-r--r--gfx/layers/ipc/ImageContainerChild.cpp70
-rw-r--r--gfx/layers/ipc/ImageContainerChild.h61
-rw-r--r--gfx/layers/ipc/ImageContainerParent.cpp31
-rw-r--r--gfx/layers/ipc/ImageContainerParent.h37
-rwxr-xr-xgfx/layers/ipc/KnowsCompositor.h90
-rw-r--r--gfx/layers/ipc/LayerAnimationUtils.cpp45
-rw-r--r--gfx/layers/ipc/LayerAnimationUtils.h30
-rw-r--r--gfx/layers/ipc/LayerTransactionChild.cpp87
-rw-r--r--gfx/layers/ipc/LayerTransactionChild.h90
-rw-r--r--gfx/layers/ipc/LayerTransactionParent.cpp1098
-rw-r--r--gfx/layers/ipc/LayerTransactionParent.h240
-rw-r--r--gfx/layers/ipc/LayerTreeOwnerTracker.cpp83
-rw-r--r--gfx/layers/ipc/LayerTreeOwnerTracker.h71
-rw-r--r--gfx/layers/ipc/LayersMessages.ipdlh499
-rw-r--r--gfx/layers/ipc/LayersSurfaces.ipdlh142
-rw-r--r--gfx/layers/ipc/PAPZ.ipdl71
-rw-r--r--gfx/layers/ipc/PAPZCTreeManager.ipdl139
-rw-r--r--gfx/layers/ipc/PCompositable.ipdl28
-rw-r--r--gfx/layers/ipc/PCompositorBridge.ipdl237
-rw-r--r--gfx/layers/ipc/PImageBridge.ipdl70
-rw-r--r--gfx/layers/ipc/PImageContainer.ipdl33
-rw-r--r--gfx/layers/ipc/PLayer.ipdl39
-rw-r--r--gfx/layers/ipc/PLayerTransaction.ipdl133
-rw-r--r--gfx/layers/ipc/PTexture.ipdl46
-rw-r--r--gfx/layers/ipc/PVideoBridge.ipdl31
-rw-r--r--gfx/layers/ipc/RemoteContentController.cpp272
-rw-r--r--gfx/layers/ipc/RemoteContentController.h96
-rw-r--r--gfx/layers/ipc/ShadowLayerChild.cpp45
-rw-r--r--gfx/layers/ipc/ShadowLayerChild.h39
-rw-r--r--gfx/layers/ipc/ShadowLayerParent.cpp138
-rw-r--r--gfx/layers/ipc/ShadowLayerParent.h58
-rw-r--r--gfx/layers/ipc/ShadowLayerUtils.h52
-rw-r--r--gfx/layers/ipc/ShadowLayerUtilsMac.cpp40
-rw-r--r--gfx/layers/ipc/ShadowLayerUtilsX11.cpp153
-rw-r--r--gfx/layers/ipc/ShadowLayerUtilsX11.h85
-rw-r--r--gfx/layers/ipc/ShadowLayers.cpp1044
-rw-r--r--gfx/layers/ipc/ShadowLayers.h465
-rw-r--r--gfx/layers/ipc/SharedPlanarYCbCrImage.cpp246
-rw-r--r--gfx/layers/ipc/SharedPlanarYCbCrImage.h60
-rw-r--r--gfx/layers/ipc/SharedRGBImage.cpp113
-rw-r--r--gfx/layers/ipc/SharedRGBImage.h59
-rw-r--r--gfx/layers/ipc/SynchronousTask.h65
-rw-r--r--gfx/layers/ipc/TextureForwarder.h79
-rw-r--r--gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h91
-rw-r--r--gfx/layers/ipc/VideoBridgeChild.cpp122
-rw-r--r--gfx/layers/ipc/VideoBridgeChild.h75
-rw-r--r--gfx/layers/ipc/VideoBridgeParent.cpp125
-rw-r--r--gfx/layers/ipc/VideoBridgeParent.h72
78 files changed, 17529 insertions, 0 deletions
diff --git a/gfx/layers/ipc/APZCTreeManagerChild.cpp b/gfx/layers/ipc/APZCTreeManagerChild.cpp
new file mode 100644
index 000000000..f5971dd38
--- /dev/null
+++ b/gfx/layers/ipc/APZCTreeManagerChild.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 "mozilla/layers/APZCTreeManagerChild.h"
+
+#include "InputData.h" // for InputData
+#include "mozilla/dom/TabParent.h" // for TabParent
+#include "mozilla/layers/APZCCallbackHelper.h" // for APZCCallbackHelper
+#include "mozilla/layers/RemoteCompositorSession.h" // for RemoteCompositorSession
+
+namespace mozilla {
+namespace layers {
+
+APZCTreeManagerChild::APZCTreeManagerChild()
+ : mCompositorSession(nullptr)
+{
+}
+
+void
+APZCTreeManagerChild::SetCompositorSession(RemoteCompositorSession* aSession)
+{
+ // Exactly one of mCompositorSession and aSession must be null (i.e. either
+ // we're setting mCompositorSession or we're clearing it).
+ MOZ_ASSERT(!mCompositorSession ^ !aSession);
+ mCompositorSession = aSession;
+}
+
+nsEventStatus
+APZCTreeManagerChild::ReceiveInputEvent(
+ InputData& aEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ switch (aEvent.mInputType) {
+ case MULTITOUCH_INPUT: {
+ MultiTouchInput& event = aEvent.AsMultiTouchInput();
+ MultiTouchInput processedEvent;
+
+ nsEventStatus res;
+ SendReceiveMultiTouchInputEvent(event,
+ &res,
+ &processedEvent,
+ aOutTargetGuid,
+ aOutInputBlockId);
+
+ event = processedEvent;
+ return res;
+ }
+ case MOUSE_INPUT: {
+ MouseInput& event = aEvent.AsMouseInput();
+ MouseInput processedEvent;
+
+ nsEventStatus res;
+ SendReceiveMouseInputEvent(event,
+ &res,
+ &processedEvent,
+ aOutTargetGuid,
+ aOutInputBlockId);
+
+ event = processedEvent;
+ return res;
+ }
+ case PANGESTURE_INPUT: {
+ PanGestureInput& event = aEvent.AsPanGestureInput();
+ PanGestureInput processedEvent;
+
+ nsEventStatus res;
+ SendReceivePanGestureInputEvent(event,
+ &res,
+ &processedEvent,
+ aOutTargetGuid,
+ aOutInputBlockId);
+
+ event = processedEvent;
+ return res;
+ }
+ case PINCHGESTURE_INPUT: {
+ PinchGestureInput& event = aEvent.AsPinchGestureInput();
+ PinchGestureInput processedEvent;
+
+ nsEventStatus res;
+ SendReceivePinchGestureInputEvent(event,
+ &res,
+ &processedEvent,
+ aOutTargetGuid,
+ aOutInputBlockId);
+
+ event = processedEvent;
+ return res;
+ }
+ case TAPGESTURE_INPUT: {
+ TapGestureInput& event = aEvent.AsTapGestureInput();
+ TapGestureInput processedEvent;
+
+ nsEventStatus res;
+ SendReceiveTapGestureInputEvent(event,
+ &res,
+ &processedEvent,
+ aOutTargetGuid,
+ aOutInputBlockId);
+
+ event = processedEvent;
+ return res;
+ }
+ case SCROLLWHEEL_INPUT: {
+ ScrollWheelInput& event = aEvent.AsScrollWheelInput();
+ ScrollWheelInput processedEvent;
+
+ nsEventStatus res;
+ SendReceiveScrollWheelInputEvent(event,
+ &res,
+ &processedEvent,
+ aOutTargetGuid,
+ aOutInputBlockId);
+
+ event = processedEvent;
+ return res;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("Invalid InputData type.");
+ return nsEventStatus_eConsumeNoDefault;
+ }
+ }
+}
+
+void
+APZCTreeManagerChild::ZoomToRect(
+ const ScrollableLayerGuid& aGuid,
+ const CSSRect& aRect,
+ const uint32_t aFlags)
+{
+ SendZoomToRect(aGuid, aRect, aFlags);
+}
+
+void
+APZCTreeManagerChild::ContentReceivedInputBlock(
+ uint64_t aInputBlockId,
+ bool aPreventDefault)
+{
+ SendContentReceivedInputBlock(aInputBlockId, aPreventDefault);
+}
+
+void
+APZCTreeManagerChild::SetTargetAPZC(
+ uint64_t aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets)
+{
+ SendSetTargetAPZC(aInputBlockId, aTargets);
+}
+
+void
+APZCTreeManagerChild::UpdateZoomConstraints(
+ const ScrollableLayerGuid& aGuid,
+ const Maybe<ZoomConstraints>& aConstraints)
+{
+ SendUpdateZoomConstraints(aGuid, aConstraints);
+}
+
+void
+APZCTreeManagerChild::CancelAnimation(const ScrollableLayerGuid &aGuid)
+{
+ SendCancelAnimation(aGuid);
+}
+
+void
+APZCTreeManagerChild::AdjustScrollForSurfaceShift(const ScreenPoint& aShift)
+{
+ SendAdjustScrollForSurfaceShift(aShift);
+}
+
+void
+APZCTreeManagerChild::SetDPI(float aDpiValue)
+{
+ SendSetDPI(aDpiValue);
+}
+
+void
+APZCTreeManagerChild::SetAllowedTouchBehavior(
+ uint64_t aInputBlockId,
+ const nsTArray<TouchBehaviorFlags>& aValues)
+{
+ SendSetAllowedTouchBehavior(aInputBlockId, aValues);
+}
+
+void
+APZCTreeManagerChild::StartScrollbarDrag(
+ const ScrollableLayerGuid& aGuid,
+ const AsyncDragMetrics& aDragMetrics)
+{
+ SendStartScrollbarDrag(aGuid, aDragMetrics);
+}
+
+void
+APZCTreeManagerChild::SetLongTapEnabled(bool aTapGestureEnabled)
+{
+ SendSetLongTapEnabled(aTapGestureEnabled);
+}
+
+void
+APZCTreeManagerChild::ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY)
+{
+ SendProcessTouchVelocity(aTimestampMs, aSpeedY);
+}
+
+void
+APZCTreeManagerChild::UpdateWheelTransaction(
+ LayoutDeviceIntPoint aRefPoint,
+ EventMessage aEventMessage)
+{
+ SendUpdateWheelTransaction(aRefPoint, aEventMessage);
+}
+
+void APZCTreeManagerChild::TransformEventRefPoint(
+ LayoutDeviceIntPoint* aRefPoint,
+ ScrollableLayerGuid* aOutTargetGuid)
+{
+ SendTransformEventRefPoint(*aRefPoint, aRefPoint, aOutTargetGuid);
+}
+
+bool
+APZCTreeManagerChild::RecvHandleTap(const TapType& aType,
+ const LayoutDevicePoint& aPoint,
+ const Modifiers& aModifiers,
+ const ScrollableLayerGuid& aGuid,
+ const uint64_t& aInputBlockId)
+{
+ MOZ_ASSERT(XRE_IsParentProcess());
+ if (mCompositorSession &&
+ mCompositorSession->RootLayerTreeId() == aGuid.mLayersId &&
+ mCompositorSession->GetContentController()) {
+ mCompositorSession->GetContentController()->HandleTap(aType, aPoint,
+ aModifiers, aGuid, aInputBlockId);
+ return true;
+ }
+ dom::TabParent* tab = dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
+ if (tab) {
+ tab->SendHandleTap(aType, aPoint, aModifiers, aGuid, aInputBlockId);
+ }
+ return true;
+}
+
+bool
+APZCTreeManagerChild::RecvNotifyPinchGesture(const PinchGestureType& aType,
+ const ScrollableLayerGuid& aGuid,
+ const LayoutDeviceCoord& aSpanChange,
+ const Modifiers& aModifiers)
+{
+ // This will only get sent from the GPU process to the parent process, so
+ // this function should never get called in the content process.
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // We want to handle it in this process regardless of what the target guid
+ // of the pinch is. This may change in the future.
+ if (mCompositorSession &&
+ mCompositorSession->GetWidget()) {
+ APZCCallbackHelper::NotifyPinchGesture(aType, aSpanChange, aModifiers, mCompositorSession->GetWidget());
+ }
+ return true;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/APZCTreeManagerChild.h b/gfx/layers/ipc/APZCTreeManagerChild.h
new file mode 100644
index 000000000..3e7a2f260
--- /dev/null
+++ b/gfx/layers/ipc/APZCTreeManagerChild.h
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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_APZCTreeManagerChild_h
+#define mozilla_layers_APZCTreeManagerChild_h
+
+#include "mozilla/layers/IAPZCTreeManager.h"
+#include "mozilla/layers/PAPZCTreeManagerChild.h"
+
+namespace mozilla {
+namespace layers {
+
+class RemoteCompositorSession;
+
+class APZCTreeManagerChild
+ : public IAPZCTreeManager
+ , public PAPZCTreeManagerChild
+{
+public:
+ APZCTreeManagerChild();
+
+ void SetCompositorSession(RemoteCompositorSession* aSession);
+
+ nsEventStatus
+ ReceiveInputEvent(
+ InputData& aEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ void
+ ZoomToRect(
+ const ScrollableLayerGuid& aGuid,
+ const CSSRect& aRect,
+ const uint32_t aFlags = DEFAULT_BEHAVIOR) override;
+
+ void
+ ContentReceivedInputBlock(
+ uint64_t aInputBlockId,
+ bool aPreventDefault) override;
+
+ void
+ SetTargetAPZC(
+ uint64_t aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets) override;
+
+ void
+ UpdateZoomConstraints(
+ const ScrollableLayerGuid& aGuid,
+ const Maybe<ZoomConstraints>& aConstraints) override;
+
+ void
+ CancelAnimation(const ScrollableLayerGuid &aGuid) override;
+
+ void
+ AdjustScrollForSurfaceShift(const ScreenPoint& aShift) override;
+
+ void
+ SetDPI(float aDpiValue) override;
+
+ void
+ SetAllowedTouchBehavior(
+ uint64_t aInputBlockId,
+ const nsTArray<TouchBehaviorFlags>& aValues) override;
+
+ void
+ StartScrollbarDrag(
+ const ScrollableLayerGuid& aGuid,
+ const AsyncDragMetrics& aDragMetrics) override;
+
+ void
+ SetLongTapEnabled(bool aTapGestureEnabled) override;
+
+ void
+ ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY) override;
+
+ void
+ TransformEventRefPoint(
+ LayoutDeviceIntPoint* aRefPoint,
+ ScrollableLayerGuid* aOutTargetGuid) override;
+
+ void
+ UpdateWheelTransaction(
+ LayoutDeviceIntPoint aRefPoint,
+ EventMessage aEventMessage) override;
+
+protected:
+ bool RecvHandleTap(const TapType& aType,
+ const LayoutDevicePoint& aPoint,
+ const Modifiers& aModifiers,
+ const ScrollableLayerGuid& aGuid,
+ const uint64_t& aInputBlockId) override;
+
+ bool RecvNotifyPinchGesture(const PinchGestureType& aType,
+ const ScrollableLayerGuid& aGuid,
+ const LayoutDeviceCoord& aSpanChange,
+ const Modifiers& aModifiers) override;
+
+ virtual
+ ~APZCTreeManagerChild() { }
+
+private:
+ MOZ_NON_OWNING_REF RemoteCompositorSession* mCompositorSession;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_APZCTreeManagerChild_h
diff --git a/gfx/layers/ipc/APZCTreeManagerParent.cpp b/gfx/layers/ipc/APZCTreeManagerParent.cpp
new file mode 100644
index 000000000..33cd6ffff
--- /dev/null
+++ b/gfx/layers/ipc/APZCTreeManagerParent.cpp
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 "mozilla/layers/APZCTreeManagerParent.h"
+
+#include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/APZThreadUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+APZCTreeManagerParent::APZCTreeManagerParent(uint64_t aLayersId, RefPtr<APZCTreeManager> aAPZCTreeManager)
+ : mLayersId(aLayersId)
+ , mTreeManager(aAPZCTreeManager)
+{
+ MOZ_ASSERT(aAPZCTreeManager != nullptr);
+}
+
+APZCTreeManagerParent::~APZCTreeManagerParent()
+{
+}
+
+void
+APZCTreeManagerParent::ChildAdopted(RefPtr<APZCTreeManager> aAPZCTreeManager)
+{
+ MOZ_ASSERT(aAPZCTreeManager != nullptr);
+ mTreeManager = aAPZCTreeManager;
+}
+
+bool
+APZCTreeManagerParent::RecvReceiveMultiTouchInputEvent(
+ const MultiTouchInput& aEvent,
+ nsEventStatus* aOutStatus,
+ MultiTouchInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ MultiTouchInput event = aEvent;
+
+ *aOutStatus = mTreeManager->ReceiveInputEvent(
+ event,
+ aOutTargetGuid,
+ aOutInputBlockId);
+ *aOutEvent = event;
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvReceiveMouseInputEvent(
+ const MouseInput& aEvent,
+ nsEventStatus* aOutStatus,
+ MouseInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ MouseInput event = aEvent;
+
+ *aOutStatus = mTreeManager->ReceiveInputEvent(
+ event,
+ aOutTargetGuid,
+ aOutInputBlockId);
+ *aOutEvent = event;
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvReceivePanGestureInputEvent(
+ const PanGestureInput& aEvent,
+ nsEventStatus* aOutStatus,
+ PanGestureInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ PanGestureInput event = aEvent;
+
+ *aOutStatus = mTreeManager->ReceiveInputEvent(
+ event,
+ aOutTargetGuid,
+ aOutInputBlockId);
+ *aOutEvent = event;
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvReceivePinchGestureInputEvent(
+ const PinchGestureInput& aEvent,
+ nsEventStatus* aOutStatus,
+ PinchGestureInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ PinchGestureInput event = aEvent;
+
+ *aOutStatus = mTreeManager->ReceiveInputEvent(
+ event,
+ aOutTargetGuid,
+ aOutInputBlockId);
+ *aOutEvent = event;
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvReceiveTapGestureInputEvent(
+ const TapGestureInput& aEvent,
+ nsEventStatus* aOutStatus,
+ TapGestureInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ TapGestureInput event = aEvent;
+
+ *aOutStatus = mTreeManager->ReceiveInputEvent(
+ event,
+ aOutTargetGuid,
+ aOutInputBlockId);
+ *aOutEvent = event;
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvReceiveScrollWheelInputEvent(
+ const ScrollWheelInput& aEvent,
+ nsEventStatus* aOutStatus,
+ ScrollWheelInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId)
+{
+ ScrollWheelInput event = aEvent;
+
+ *aOutStatus = mTreeManager->ReceiveInputEvent(
+ event,
+ aOutTargetGuid,
+ aOutInputBlockId);
+ *aOutEvent = event;
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvZoomToRect(
+ const ScrollableLayerGuid& aGuid,
+ const CSSRect& aRect,
+ const uint32_t& aFlags)
+{
+ if (aGuid.mLayersId != mLayersId) {
+ // Guard against bad data from hijacked child processes
+ NS_ERROR("Unexpected layers id in RecvZoomToRect; dropping message...");
+ return false;
+ }
+
+ mTreeManager->ZoomToRect(aGuid, aRect, aFlags);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvContentReceivedInputBlock(
+ const uint64_t& aInputBlockId,
+ const bool& aPreventDefault)
+{
+ APZThreadUtils::RunOnControllerThread(
+ NewRunnableMethod<uint64_t, bool>(mTreeManager,
+ &IAPZCTreeManager::ContentReceivedInputBlock,
+ aInputBlockId,
+ aPreventDefault));
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvSetTargetAPZC(
+ const uint64_t& aInputBlockId,
+ nsTArray<ScrollableLayerGuid>&& aTargets)
+{
+ for (size_t i = 0; i < aTargets.Length(); i++) {
+ if (aTargets[i].mLayersId != mLayersId) {
+ // Guard against bad data from hijacked child processes
+ NS_ERROR("Unexpected layers id in RecvSetTargetAPZC; dropping message...");
+ return false;
+ }
+ }
+ APZThreadUtils::RunOnControllerThread(NewRunnableMethod
+ <uint64_t,
+ StoreCopyPassByRRef<nsTArray<ScrollableLayerGuid>>>
+ (mTreeManager, &IAPZCTreeManager::SetTargetAPZC, aInputBlockId, aTargets));
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvUpdateZoomConstraints(
+ const ScrollableLayerGuid& aGuid,
+ const MaybeZoomConstraints& aConstraints)
+{
+ if (aGuid.mLayersId != mLayersId) {
+ // Guard against bad data from hijacked child processes
+ NS_ERROR("Unexpected layers id in RecvUpdateZoomConstraints; dropping message...");
+ return false;
+ }
+
+ mTreeManager->UpdateZoomConstraints(aGuid, aConstraints);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvCancelAnimation(const ScrollableLayerGuid& aGuid)
+{
+ if (aGuid.mLayersId != mLayersId) {
+ // Guard against bad data from hijacked child processes
+ NS_ERROR("Unexpected layers id in RecvCancelAnimation; dropping message...");
+ return false;
+ }
+
+ mTreeManager->CancelAnimation(aGuid);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvAdjustScrollForSurfaceShift(const ScreenPoint& aShift)
+{
+ mTreeManager->AdjustScrollForSurfaceShift(aShift);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvSetDPI(const float& aDpiValue)
+{
+ mTreeManager->SetDPI(aDpiValue);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvSetAllowedTouchBehavior(
+ const uint64_t& aInputBlockId,
+ nsTArray<TouchBehaviorFlags>&& aValues)
+{
+ APZThreadUtils::RunOnControllerThread(NewRunnableMethod
+ <uint64_t,
+ StoreCopyPassByRRef<nsTArray<TouchBehaviorFlags>>>
+ (mTreeManager,
+ &IAPZCTreeManager::SetAllowedTouchBehavior,
+ aInputBlockId, Move(aValues)));
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvStartScrollbarDrag(
+ const ScrollableLayerGuid& aGuid,
+ const AsyncDragMetrics& aDragMetrics)
+{
+ if (aGuid.mLayersId != mLayersId) {
+ // Guard against bad data from hijacked child processes
+ NS_ERROR("Unexpected layers id in RecvStartScrollbarDrag; dropping message...");
+ return false;
+ }
+
+ APZThreadUtils::RunOnControllerThread(
+ NewRunnableMethod<ScrollableLayerGuid, AsyncDragMetrics>(
+ mTreeManager,
+ &IAPZCTreeManager::StartScrollbarDrag,
+ aGuid, aDragMetrics));
+
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvSetLongTapEnabled(const bool& aTapGestureEnabled)
+{
+ mTreeManager->SetLongTapEnabled(aTapGestureEnabled);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvProcessTouchVelocity(
+ const uint32_t& aTimestampMs,
+ const float& aSpeedY)
+{
+ mTreeManager->ProcessTouchVelocity(aTimestampMs, aSpeedY);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvUpdateWheelTransaction(
+ const LayoutDeviceIntPoint& aRefPoint,
+ const EventMessage& aEventMessage)
+{
+ mTreeManager->UpdateWheelTransaction(aRefPoint, aEventMessage);
+ return true;
+}
+
+bool
+APZCTreeManagerParent::RecvTransformEventRefPoint(
+ const LayoutDeviceIntPoint& aRefPoint,
+ LayoutDeviceIntPoint* aOutRefPoint,
+ ScrollableLayerGuid* aOutTargetGuid)
+{
+ LayoutDeviceIntPoint refPoint = aRefPoint;
+ mTreeManager->TransformEventRefPoint(&refPoint, aOutTargetGuid);
+ *aOutRefPoint = refPoint;
+
+ return true;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/APZCTreeManagerParent.h b/gfx/layers/ipc/APZCTreeManagerParent.h
new file mode 100644
index 000000000..f2d3aec57
--- /dev/null
+++ b/gfx/layers/ipc/APZCTreeManagerParent.h
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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_APZCTreeManagerParent_h
+#define mozilla_layers_APZCTreeManagerParent_h
+
+#include "mozilla/layers/PAPZCTreeManagerParent.h"
+
+namespace mozilla {
+namespace layers {
+
+class APZCTreeManager;
+
+class APZCTreeManagerParent
+ : public PAPZCTreeManagerParent
+{
+public:
+
+ explicit APZCTreeManagerParent(uint64_t aLayersId, RefPtr<APZCTreeManager> aAPZCTreeManager);
+ virtual ~APZCTreeManagerParent();
+
+ uint64_t LayersId() const { return mLayersId; }
+
+ /**
+ * Called when the layer tree that this protocol is connected to
+ * is adopted by another compositor, and we need to switch APZCTreeManagers.
+ */
+ void ChildAdopted(RefPtr<APZCTreeManager> aAPZCTreeManager);
+
+ bool
+ RecvReceiveMultiTouchInputEvent(
+ const MultiTouchInput& aEvent,
+ nsEventStatus* aOutStatus,
+ MultiTouchInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ bool
+ RecvReceiveMouseInputEvent(
+ const MouseInput& aEvent,
+ nsEventStatus* aOutStatus,
+ MouseInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ bool
+ RecvReceivePanGestureInputEvent(
+ const PanGestureInput& aEvent,
+ nsEventStatus* aOutStatus,
+ PanGestureInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ bool
+ RecvReceivePinchGestureInputEvent(
+ const PinchGestureInput& aEvent,
+ nsEventStatus* aOutStatus,
+ PinchGestureInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ bool
+ RecvReceiveTapGestureInputEvent(
+ const TapGestureInput& aEvent,
+ nsEventStatus* aOutStatus,
+ TapGestureInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ bool
+ RecvReceiveScrollWheelInputEvent(
+ const ScrollWheelInput& aEvent,
+ nsEventStatus* aOutStatus,
+ ScrollWheelInput* aOutEvent,
+ ScrollableLayerGuid* aOutTargetGuid,
+ uint64_t* aOutInputBlockId) override;
+
+ bool
+ RecvZoomToRect(
+ const ScrollableLayerGuid& aGuid,
+ const CSSRect& aRect,
+ const uint32_t& aFlags) override;
+
+ bool
+ RecvContentReceivedInputBlock(
+ const uint64_t& aInputBlockId,
+ const bool& aPreventDefault) override;
+
+ bool
+ RecvSetTargetAPZC(
+ const uint64_t& aInputBlockId,
+ nsTArray<ScrollableLayerGuid>&& aTargets) override;
+
+ bool
+ RecvUpdateZoomConstraints(
+ const ScrollableLayerGuid& aGuid,
+ const MaybeZoomConstraints& aConstraints) override;
+
+ bool
+ RecvCancelAnimation(const ScrollableLayerGuid& aGuid) override;
+
+ bool
+ RecvAdjustScrollForSurfaceShift(const ScreenPoint& aShift) override;
+
+ bool
+ RecvSetDPI(const float& aDpiValue) override;
+
+ bool
+ RecvSetAllowedTouchBehavior(
+ const uint64_t& aInputBlockId,
+ nsTArray<TouchBehaviorFlags>&& aValues) override;
+
+ bool
+ RecvStartScrollbarDrag(
+ const ScrollableLayerGuid& aGuid,
+ const AsyncDragMetrics& aDragMetrics) override;
+
+ bool
+ RecvSetLongTapEnabled(const bool& aTapGestureEnabled) override;
+
+ bool
+ RecvProcessTouchVelocity(
+ const uint32_t& aTimestampMs,
+ const float& aSpeedY) override;
+
+ bool
+ RecvUpdateWheelTransaction(
+ const LayoutDeviceIntPoint& aRefPoint,
+ const EventMessage& aEventMessage) override;
+
+ bool
+ RecvTransformEventRefPoint(
+ const LayoutDeviceIntPoint& aRefPoint,
+ LayoutDeviceIntPoint* aOutRefPoint,
+ ScrollableLayerGuid* aOutTargetGuid) override;
+
+ void
+ ActorDestroy(ActorDestroyReason aWhy) override { }
+
+private:
+ uint64_t mLayersId;
+ RefPtr<APZCTreeManager> mTreeManager;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_APZCTreeManagerParent_h
diff --git a/gfx/layers/ipc/APZChild.cpp b/gfx/layers/ipc/APZChild.cpp
new file mode 100644
index 000000000..2dd24d4cd
--- /dev/null
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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 "mozilla/layers/APZChild.h"
+#include "mozilla/layers/GeckoContentController.h"
+
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
+
+#include "InputData.h" // for InputData
+
+namespace mozilla {
+namespace layers {
+
+APZChild::APZChild(RefPtr<GeckoContentController> aController)
+ : mController(aController)
+{
+ MOZ_ASSERT(mController);
+}
+
+APZChild::~APZChild()
+{
+ if (mController) {
+ mController->Destroy();
+ mController = nullptr;
+ }
+}
+
+bool
+APZChild::RecvRequestContentRepaint(const FrameMetrics& aFrameMetrics)
+{
+ MOZ_ASSERT(mController->IsRepaintThread());
+
+ mController->RequestContentRepaint(aFrameMetrics);
+ return true;
+}
+
+bool
+APZChild::RecvUpdateOverscrollVelocity(const float& aX, const float& aY, const bool& aIsRootContent)
+{
+ mController->UpdateOverscrollVelocity(aX, aY, aIsRootContent);
+ return true;
+}
+
+bool
+APZChild::RecvUpdateOverscrollOffset(const float& aX, const float& aY, const bool& aIsRootContent)
+{
+ mController->UpdateOverscrollOffset(aX, aY, aIsRootContent);
+ return true;
+}
+
+bool
+APZChild::RecvSetScrollingRootContent(const bool& aIsRootContent)
+{
+ mController->SetScrollingRootContent(aIsRootContent);
+ return true;
+}
+
+bool
+APZChild::RecvNotifyMozMouseScrollEvent(const ViewID& aScrollId,
+ const nsString& aEvent)
+{
+ mController->NotifyMozMouseScrollEvent(aScrollId, aEvent);
+ return true;
+}
+
+bool
+APZChild::RecvNotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
+ const APZStateChange& aChange,
+ const int& aArg)
+{
+ mController->NotifyAPZStateChange(aGuid, aChange, aArg);
+ return true;
+}
+
+bool
+APZChild::RecvNotifyFlushComplete()
+{
+ MOZ_ASSERT(mController->IsRepaintThread());
+
+ mController->NotifyFlushComplete();
+ return true;
+}
+
+bool
+APZChild::RecvDestroy()
+{
+ // mController->Destroy will be called in the destructor
+ PAPZChild::Send__delete__(this);
+ return true;
+}
+
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/APZChild.h b/gfx/layers/ipc/APZChild.h
new file mode 100644
index 000000000..57865ee6d
--- /dev/null
+++ b/gfx/layers/ipc/APZChild.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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_APZChild_h
+#define mozilla_layers_APZChild_h
+
+#include "mozilla/layers/PAPZChild.h"
+
+namespace mozilla {
+
+namespace layers {
+
+class GeckoContentController;
+
+/**
+ * APZChild implements PAPZChild and is used to remote a GeckoContentController
+ * that lives in a different process than where APZ lives.
+ */
+class APZChild final : public PAPZChild
+{
+public:
+ explicit APZChild(RefPtr<GeckoContentController> aController);
+ ~APZChild();
+
+ bool RecvRequestContentRepaint(const FrameMetrics& frame) override;
+
+ bool RecvUpdateOverscrollVelocity(const float& aX, const float& aY, const bool& aIsRootContent) override;
+
+ bool RecvUpdateOverscrollOffset(const float& aX, const float& aY, const bool& aIsRootContent) override;
+
+ bool RecvSetScrollingRootContent(const bool& aIsRootContent) override;
+
+ bool RecvNotifyMozMouseScrollEvent(const ViewID& aScrollId,
+ const nsString& aEvent) override;
+
+ bool RecvNotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
+ const APZStateChange& aChange,
+ const int& aArg) override;
+
+ bool RecvNotifyFlushComplete() override;
+
+ bool RecvDestroy() override;
+
+private:
+ RefPtr<GeckoContentController> mController;
+};
+
+} // namespace layers
+
+} // namespace mozilla
+
+#endif // mozilla_layers_APZChild_h
diff --git a/gfx/layers/ipc/CompositableForwarder.cpp b/gfx/layers/ipc/CompositableForwarder.cpp
new file mode 100644
index 000000000..20f2f61ae
--- /dev/null
+++ b/gfx/layers/ipc/CompositableForwarder.cpp
@@ -0,0 +1,28 @@
+/* -*- 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 "CompositableForwarder.h"
+#include "mozilla/layers/CompositableChild.h"
+
+namespace mozilla {
+namespace layers {
+
+void
+CompositableForwarder::Destroy(CompositableChild* aCompositable)
+{
+ AssertInForwarderThread();
+
+ if (!aCompositable->CanSend()) {
+ return;
+ }
+
+ if (!DestroyInTransaction(aCompositable, false)) {
+ aCompositable->SendDestroy();
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h
new file mode 100644
index 000000000..b31754b5a
--- /dev/null
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -0,0 +1,127 @@
+/* -*- 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_COMPOSITABLEFORWARDER
+#define MOZILLA_LAYERS_COMPOSITABLEFORWARDER
+
+#include <stdint.h> // for int32_t, uint64_t
+#include "gfxTypes.h"
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/UniquePtr.h"
+#include "mozilla/layers/CompositableClient.h" // for CompositableClient
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
+#include "mozilla/layers/LayersTypes.h" // for LayersBackend
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
+#include "nsRegion.h" // for nsIntRegion
+#include "mozilla/gfx/Rect.h"
+#include "nsHashKeys.h"
+#include "nsTHashtable.h"
+
+namespace mozilla {
+namespace layers {
+
+class CompositableClient;
+class ImageContainer;
+class SurfaceDescriptor;
+class SurfaceDescriptorTiles;
+class ThebesBufferData;
+class PTextureChild;
+
+/**
+ * A transaction is a set of changes that happenned on the content side, that
+ * should be sent to the compositor side.
+ * CompositableForwarder is an interface to manage a transaction of
+ * compositable objetcs.
+ *
+ * ShadowLayerForwarder is an example of a CompositableForwarder (that can
+ * additionally forward modifications of the Layer tree).
+ * ImageBridgeChild is another CompositableForwarder.
+ *
+ * CompositableForwarder implements KnowsCompositor for simplicity as all
+ * implementations of CompositableForwarder currently also implement KnowsCompositor.
+ * This dependency could be split if we add new use cases.
+ */
+class CompositableForwarder : public KnowsCompositor
+{
+public:
+ /**
+ * Setup the IPDL actor for aCompositable to be part of layers
+ * transactions.
+ */
+ virtual void Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer = nullptr) = 0;
+
+ /**
+ * Tell the CompositableHost on the compositor side what TiledLayerBuffer to
+ * use for the next composition.
+ */
+ virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
+ const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
+
+ /**
+ * Communicate to the compositor that aRegion in the texture identified by
+ * aCompositable and aIdentifier has been updated to aThebesBuffer.
+ */
+ virtual void UpdateTextureRegion(CompositableClient* aCompositable,
+ const ThebesBufferData& aThebesBufferData,
+ const nsIntRegion& aUpdatedRegion) = 0;
+
+ virtual void Destroy(CompositableChild* aCompositable);
+
+ virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) = 0;
+ virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) = 0;
+
+ /**
+ * Tell the CompositableHost on the compositor side to remove the texture
+ * from the CompositableHost.
+ * This function does not delete the TextureHost corresponding to the
+ * TextureClient passed in parameter.
+ * When the TextureClient has TEXTURE_DEALLOCATE_CLIENT flag,
+ * the transaction becomes synchronous.
+ */
+ virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
+ TextureClient* aTexture) = 0;
+
+ struct TimedTextureClient {
+ TimedTextureClient()
+ : mTextureClient(nullptr), mFrameID(0), mProducerID(0) {}
+
+ TextureClient* mTextureClient;
+ TimeStamp mTimeStamp;
+ nsIntRect mPictureRect;
+ int32_t mFrameID;
+ int32_t mProducerID;
+ };
+ /**
+ * Tell the CompositableHost on the compositor side what textures to use for
+ * the next composition.
+ */
+ virtual void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) = 0;
+ virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
+ TextureClient* aClientOnBlack,
+ TextureClient* aClientOnWhite) = 0;
+
+ virtual void UpdateFwdTransactionId() = 0;
+ virtual uint64_t GetFwdTransactionId() = 0;
+
+ virtual bool InForwarderThread() = 0;
+
+ void AssertInForwarderThread() {
+ MOZ_ASSERT(InForwarderThread());
+ }
+
+protected:
+ nsTArray<RefPtr<TextureClient> > mTexturesToRemove;
+ nsTArray<RefPtr<CompositableClient>> mCompositableClientsToRemove;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/CompositableTransactionParent.cpp b/gfx/layers/ipc/CompositableTransactionParent.cpp
new file mode 100644
index 000000000..135011101
--- /dev/null
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -0,0 +1,245 @@
+/* -*- 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 "CompositableTransactionParent.h"
+#include "CompositableHost.h" // for CompositableParent, etc
+#include "CompositorBridgeParent.h" // for CompositorBridgeParent
+#include "GLContext.h" // for GLContext
+#include "Layers.h" // for Layer
+#include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/RefPtr.h" // for RefPtr
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/ContentHost.h" // for ContentHostBase
+#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
+#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
+#include "mozilla/layers/TextureHost.h" // for TextureHost
+#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
+#include "mozilla/layers/TiledContentHost.h"
+#include "mozilla/layers/PaintedLayerComposite.h"
+#include "mozilla/mozalloc.h" // for operator delete
+#include "mozilla/Unused.h"
+#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
+#include "nsRegion.h" // for nsIntRegion
+
+namespace mozilla {
+namespace layers {
+
+class ClientTiledLayerBuffer;
+class Compositor;
+
+// This function can in some cases fail and return false without it being a bug.
+// This can theoretically happen if the ImageBridge sends frames before
+// we created the layer tree. Since we can't enforce that the layer
+// tree is already created before ImageBridge operates, there isn't much
+// we can do about it, but in practice it is very rare.
+// Typically when a tab with a video is dragged from a window to another,
+// there can be a short time when the video is still sending frames
+// asynchonously while the layer tree is not reconstructed. It's not a
+// big deal.
+// Note that Layers transactions do not need to call this because they always
+// schedule the composition, in LayerManagerComposite::EndTransaction.
+static bool
+ScheduleComposition(CompositableHost* aCompositable)
+{
+ uint64_t id = aCompositable->GetCompositorID();
+ if (!id) {
+ return false;
+ }
+ CompositorBridgeParent* cp = CompositorBridgeParent::GetCompositorBridgeParent(id);
+ if (!cp) {
+ return false;
+ }
+ cp->ScheduleComposition();
+ return true;
+}
+
+bool
+CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation& aEdit,
+ EditReplyVector& replyv)
+{
+ // Ignore all operations on compositables created on stale compositors. We
+ // return true because the child is unable to handle errors.
+ CompositableHost* compositable = CompositableHost::FromIPDLActor(aEdit.compositableParent());
+ if (compositable->GetCompositor() && !compositable->GetCompositor()->IsValid()) {
+ return true;
+ }
+
+ switch (aEdit.detail().type()) {
+ case CompositableOperationDetail::TOpPaintTextureRegion: {
+ MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
+
+ const OpPaintTextureRegion& op = aEdit.detail().get_OpPaintTextureRegion();
+ Layer* layer = compositable->GetLayer();
+ if (!layer || layer->GetType() != Layer::TYPE_PAINTED) {
+ return false;
+ }
+ PaintedLayerComposite* thebes = static_cast<PaintedLayerComposite*>(layer);
+
+ const ThebesBufferData& bufferData = op.bufferData();
+
+ RenderTraceInvalidateStart(thebes, "FF00FF", op.updatedRegion().GetBounds());
+
+ nsIntRegion frontUpdatedRegion;
+ if (!compositable->UpdateThebes(bufferData,
+ op.updatedRegion(),
+ thebes->GetValidRegion(),
+ &frontUpdatedRegion))
+ {
+ return false;
+ }
+ replyv.push_back(
+ OpContentBufferSwap(aEdit.compositableParent(), nullptr, frontUpdatedRegion));
+
+ RenderTraceInvalidateEnd(thebes, "FF00FF");
+ break;
+ }
+ case CompositableOperationDetail::TOpUseTiledLayerBuffer: {
+ MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
+ const OpUseTiledLayerBuffer& op = aEdit.detail().get_OpUseTiledLayerBuffer();
+ TiledContentHost* tiledHost = compositable->AsTiledContentHost();
+
+ NS_ASSERTION(tiledHost, "The compositable is not tiled");
+
+ const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
+
+ bool success = tiledHost->UseTiledLayerBuffer(this, tileDesc);
+
+ const InfallibleTArray<TileDescriptor>& tileDescriptors = tileDesc.tiles();
+ for (size_t i = 0; i < tileDescriptors.Length(); i++) {
+ const TileDescriptor& tileDesc = tileDescriptors[i];
+ if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) {
+ continue;
+ }
+ const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
+ RefPtr<TextureHost> texture = TextureHost::AsTextureHost(texturedDesc.textureParent());
+ if (texture) {
+ texture->SetLastFwdTransactionId(mFwdTransactionId);
+ // Make sure that each texture was handled by the compositable
+ // because the recycling logic depends on it.
+ MOZ_ASSERT(texture->NumCompositableRefs() > 0);
+ }
+ if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
+ texture = TextureHost::AsTextureHost(texturedDesc.textureOnWhite().get_PTextureParent());
+ if (texture) {
+ texture->SetLastFwdTransactionId(mFwdTransactionId);
+ // Make sure that each texture was handled by the compositable
+ // because the recycling logic depends on it.
+ MOZ_ASSERT(texture->NumCompositableRefs() > 0);
+ }
+ }
+ }
+ if (!success) {
+ return false;
+ }
+ break;
+ }
+ case CompositableOperationDetail::TOpRemoveTexture: {
+ const OpRemoveTexture& op = aEdit.detail().get_OpRemoveTexture();
+
+ RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
+
+ MOZ_ASSERT(tex.get());
+ compositable->RemoveTextureHost(tex);
+ break;
+ }
+ case CompositableOperationDetail::TOpUseTexture: {
+ const OpUseTexture& op = aEdit.detail().get_OpUseTexture();
+
+ AutoTArray<CompositableHost::TimedTexture,4> textures;
+ for (auto& timedTexture : op.textures()) {
+ CompositableHost::TimedTexture* t = textures.AppendElement();
+ t->mTexture =
+ TextureHost::AsTextureHost(timedTexture.textureParent());
+ MOZ_ASSERT(t->mTexture);
+ t->mTimeStamp = timedTexture.timeStamp();
+ t->mPictureRect = timedTexture.picture();
+ t->mFrameID = timedTexture.frameID();
+ t->mProducerID = timedTexture.producerID();
+ t->mTexture->DeserializeReadLock(timedTexture.sharedLock(), this);
+ }
+ if (textures.Length() > 0) {
+ compositable->UseTextureHost(textures);
+
+ for (auto& timedTexture : op.textures()) {
+ RefPtr<TextureHost> texture = TextureHost::AsTextureHost(timedTexture.textureParent());
+ if (texture) {
+ texture->SetLastFwdTransactionId(mFwdTransactionId);
+ // Make sure that each texture was handled by the compositable
+ // because the recycling logic depends on it.
+ MOZ_ASSERT(texture->NumCompositableRefs() > 0);
+ }
+ }
+ }
+
+ if (UsesImageBridge() && compositable->GetLayer()) {
+ ScheduleComposition(compositable);
+ }
+ break;
+ }
+ case CompositableOperationDetail::TOpUseComponentAlphaTextures: {
+ const OpUseComponentAlphaTextures& op = aEdit.detail().get_OpUseComponentAlphaTextures();
+ RefPtr<TextureHost> texOnBlack = TextureHost::AsTextureHost(op.textureOnBlackParent());
+ RefPtr<TextureHost> texOnWhite = TextureHost::AsTextureHost(op.textureOnWhiteParent());
+ texOnBlack->DeserializeReadLock(op.sharedLockBlack(), this);
+ texOnWhite->DeserializeReadLock(op.sharedLockWhite(), this);
+
+ MOZ_ASSERT(texOnBlack && texOnWhite);
+ compositable->UseComponentAlphaTextures(texOnBlack, texOnWhite);
+
+ if (texOnBlack) {
+ texOnBlack->SetLastFwdTransactionId(mFwdTransactionId);
+ // Make sure that each texture was handled by the compositable
+ // because the recycling logic depends on it.
+ MOZ_ASSERT(texOnBlack->NumCompositableRefs() > 0);
+ }
+
+ if (texOnWhite) {
+ texOnWhite->SetLastFwdTransactionId(mFwdTransactionId);
+ // Make sure that each texture was handled by the compositable
+ // because the recycling logic depends on it.
+ MOZ_ASSERT(texOnWhite->NumCompositableRefs() > 0);
+ }
+
+ if (UsesImageBridge()) {
+ ScheduleComposition(compositable);
+ }
+ break;
+ }
+ default: {
+ MOZ_ASSERT(false, "bad type");
+ }
+ }
+
+ return true;
+}
+
+void
+CompositableParentManager::DestroyActor(const OpDestroy& aOp)
+{
+ switch (aOp.type()) {
+ case OpDestroy::TPTextureParent: {
+ auto actor = aOp.get_PTextureParent();
+ TextureHost::ReceivedDestroy(actor);
+ break;
+ }
+ case OpDestroy::TPCompositableParent: {
+ auto actor = aOp.get_PCompositableParent();
+ CompositableHost::ReceivedDestroy(actor);
+ break;
+ }
+ default: {
+ MOZ_ASSERT(false, "unsupported type");
+ }
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
+
diff --git a/gfx/layers/ipc/CompositableTransactionParent.h b/gfx/layers/ipc/CompositableTransactionParent.h
new file mode 100644
index 000000000..ca676c115
--- /dev/null
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -0,0 +1,55 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_LAYERS_COMPOSITABLETRANSACTIONPARENT_H
+#define MOZILLA_LAYERS_COMPOSITABLETRANSACTIONPARENT_H
+
+#include <vector> // for vector
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
+#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
+
+namespace mozilla {
+namespace layers {
+
+class CompositableHost;
+
+typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
+
+// Since PCompositble has two potential manager protocols, we can't just call
+// the Manager() method usually generated when there's one manager protocol,
+// so both manager protocols implement this and we keep a reference to them
+// through this interface.
+class CompositableParentManager : public HostIPCAllocator
+{
+public:
+ CompositableParentManager() {}
+
+ void DestroyActor(const OpDestroy& aOp);
+
+ void UpdateFwdTransactionId(uint64_t aTransactionId)
+ {
+ MOZ_ASSERT(mFwdTransactionId < aTransactionId);
+ mFwdTransactionId = aTransactionId;
+ }
+
+ uint64_t GetFwdTransactionId() { return mFwdTransactionId; }
+
+protected:
+ /**
+ * Handle the IPDL messages that affect PCompositable actors.
+ */
+ bool ReceiveCompositableUpdate(const CompositableOperation& aEdit,
+ EditReplyVector& replyv);
+
+ uint64_t mFwdTransactionId = 0;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/CompositorBench.cpp b/gfx/layers/ipc/CompositorBench.cpp
new file mode 100644
index 000000000..945adafc1
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBench.cpp
@@ -0,0 +1,345 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "CompositorBench.h"
+
+#ifdef MOZ_COMPOSITOR_BENCH
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/Compositor.h"
+#include "mozilla/layers/Effects.h"
+#include "mozilla/TimeStamp.h"
+#include "gfxPrefs.h"
+#include <math.h>
+#include "GeckoProfiler.h"
+
+#define TEST_STEPS 1000
+#define DURATION_THRESHOLD 30
+#define THRESHOLD_ABORT_COUNT 5
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+static float SimplePseudoRandom(int aStep, int aCount) {
+ srand(aStep * 1000 + aCount);
+ return static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
+}
+
+class BenchTest {
+public:
+ BenchTest(const char* aTestName)
+ : mTestName(aTestName)
+ {}
+
+ virtual ~BenchTest() {}
+
+ virtual void Setup(Compositor* aCompositor, size_t aStep) {}
+ virtual void Teardown(Compositor* aCompositor) {}
+ virtual void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) = 0;
+
+ const char* ToString() { return mTestName; }
+private:
+ const char* mTestName;
+};
+
+static void
+DrawFrameTrivialQuad(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep, const EffectChain& effects) {
+ for (size_t i = 0; i < aStep * 10; i++) {
+ const gfx::Rect& rect = gfx::Rect(i % (int)aScreenRect.width,
+ (int)(i / aScreenRect.height),
+ 1, 1);
+ const gfx::Rect& clipRect = aScreenRect;
+
+ float opacity = 1.f;
+
+ gfx::Matrix transform2d;
+
+ gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
+
+ aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
+ }
+}
+
+static void
+DrawFrameStressQuad(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep, const EffectChain& effects)
+{
+ for (size_t i = 0; i < aStep * 10; i++) {
+ const gfx::Rect& rect = gfx::Rect(aScreenRect.width * SimplePseudoRandom(i, 0),
+ aScreenRect.height * SimplePseudoRandom(i, 1),
+ aScreenRect.width * SimplePseudoRandom(i, 2),
+ aScreenRect.height * SimplePseudoRandom(i, 3));
+ const gfx::Rect& clipRect = aScreenRect;
+
+ float opacity = 1.f;
+
+ gfx::Matrix transform2d;
+ transform2d = transform2d.PreRotate(SimplePseudoRandom(i, 4) * 70.f);
+
+ gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
+
+ aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
+ }
+}
+
+class EffectSolidColorBench : public BenchTest {
+public:
+ EffectSolidColorBench()
+ : BenchTest("EffectSolidColorBench (clear frame with EffectSolidColor)")
+ {}
+
+ void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+ float tmp;
+ float red = modff(aStep * 0.03f, &tmp);
+ EffectChain effects;
+ effects.mPrimaryEffect =
+ new EffectSolidColor(gfx::Color(red, 0.4f, 0.4f, 1.0f));
+
+ const gfx::Rect& rect = aScreenRect;
+ const gfx::Rect& clipRect = aScreenRect;
+
+ float opacity = 1.f;
+
+ gfx::Matrix4x4 transform;
+ aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
+ }
+};
+
+class EffectSolidColorTrivialBench : public BenchTest {
+public:
+ EffectSolidColorTrivialBench()
+ : BenchTest("EffectSolidColorTrivialBench (10s 1x1 EffectSolidColor)")
+ {}
+
+ void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+ EffectChain effects;
+ effects.mPrimaryEffect = CreateEffect(aStep);
+
+ DrawFrameTrivialQuad(aCompositor, aScreenRect, aStep, effects);
+ }
+
+ already_AddRefed<Effect> CreateEffect(size_t i) {
+ float tmp;
+ float red = modff(i * 0.03f, &tmp);
+ EffectChain effects;
+ return MakeAndAddRef<EffectSolidColor>(gfx::Color(red, 0.4f, 0.4f, 1.0f));
+ }
+};
+
+class EffectSolidColorStressBench : public BenchTest {
+public:
+ EffectSolidColorStressBench()
+ : BenchTest("EffectSolidColorStressBench (10s various EffectSolidColor)")
+ {}
+
+ void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+ EffectChain effects;
+ effects.mPrimaryEffect = CreateEffect(aStep);
+
+ DrawFrameStressQuad(aCompositor, aScreenRect, aStep, effects);
+ }
+
+ already_AddRefed<Effect> CreateEffect(size_t i) {
+ float tmp;
+ float red = modff(i * 0.03f, &tmp);
+ EffectChain effects;
+ return MakeAndAddRef<EffectSolidColor>(gfx::Color(red, 0.4f, 0.4f, 1.0f));
+ }
+};
+
+class UploadBench : public BenchTest {
+public:
+ UploadBench()
+ : BenchTest("Upload Bench (10s 256x256 upload)")
+ {}
+
+ uint32_t* mBuf;
+ RefPtr<DataSourceSurface> mSurface;
+ RefPtr<DataTextureSource> mTexture;
+
+ virtual void Setup(Compositor* aCompositor, size_t aStep) {
+ int bytesPerPixel = 4;
+ int w = 256;
+ int h = 256;
+ mBuf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
+
+ mSurface = Factory::CreateWrappingDataSourceSurface(
+ reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
+ mTexture = aCompositor->CreateDataTextureSource();
+ }
+
+ virtual void Teardown(Compositor* aCompositor) {
+ mSurface = nullptr;
+ mTexture = nullptr;
+ free(mBuf);
+ }
+
+ void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+ for (size_t i = 0; i < aStep * 10; i++) {
+ mTexture->Update(mSurface);
+ }
+ }
+};
+
+class TrivialTexturedQuadBench : public BenchTest {
+public:
+ TrivialTexturedQuadBench()
+ : BenchTest("Trvial Textured Quad (10s 256x256 quads)")
+ {}
+
+ uint32_t* mBuf;
+ RefPtr<DataSourceSurface> mSurface;
+ RefPtr<DataTextureSource> mTexture;
+
+ virtual void Setup(Compositor* aCompositor, size_t aStep) {
+ int bytesPerPixel = 4;
+ size_t w = 256;
+ size_t h = 256;
+ mBuf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
+ for (size_t i = 0; i < w * h; i++) {
+ mBuf[i] = 0xFF00008F;
+ }
+
+ mSurface = Factory::CreateWrappingDataSourceSurface(
+ reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
+ mTexture = aCompositor->CreateDataTextureSource();
+ mTexture->Update(mSurface);
+ }
+
+ void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+ EffectChain effects;
+ effects.mPrimaryEffect = CreateEffect(aStep);
+
+ DrawFrameTrivialQuad(aCompositor, aScreenRect, aStep, effects);
+ }
+
+ virtual void Teardown(Compositor* aCompositor) {
+ mSurface = nullptr;
+ mTexture = nullptr;
+ free(mBuf);
+ }
+
+ already_AddRefed<Effect> CreateEffect(size_t i) {
+ return CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mTexture,
+ SamplingFilter::POINT, true);
+ }
+};
+
+class StressTexturedQuadBench : public BenchTest {
+public:
+ StressTexturedQuadBench()
+ : BenchTest("Stress Textured Quad (10s 256x256 quads)")
+ {}
+
+ uint32_t* mBuf;
+ RefPtr<DataSourceSurface> mSurface;
+ RefPtr<DataTextureSource> mTexture;
+
+ virtual void Setup(Compositor* aCompositor, size_t aStep) {
+ int bytesPerPixel = 4;
+ size_t w = 256;
+ size_t h = 256;
+ mBuf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
+ for (size_t i = 0; i < w * h; i++) {
+ mBuf[i] = 0xFF00008F;
+ }
+
+ mSurface = Factory::CreateWrappingDataSourceSurface(
+ reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
+ mTexture = aCompositor->CreateDataTextureSource();
+ mTexture->Update(mSurface);
+ }
+
+ void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+ EffectChain effects;
+ effects.mPrimaryEffect = CreateEffect(aStep);
+
+ DrawFrameStressQuad(aCompositor, aScreenRect, aStep, effects);
+ }
+
+ virtual void Teardown(Compositor* aCompositor) {
+ mSurface = nullptr;
+ mTexture = nullptr;
+ free(mBuf);
+ }
+
+ virtual already_AddRefed<Effect> CreateEffect(size_t i) {
+ return CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mTexture,
+ SamplingFilter::POINT, true);
+ }
+};
+
+static void RunCompositorBench(Compositor* aCompositor, const gfx::Rect& aScreenRect)
+{
+ std::vector<BenchTest*> tests;
+
+ tests.push_back(new EffectSolidColorBench());
+ tests.push_back(new UploadBench());
+ tests.push_back(new EffectSolidColorTrivialBench());
+ tests.push_back(new EffectSolidColorStressBench());
+ tests.push_back(new TrivialTexturedQuadBench());
+ tests.push_back(new StressTexturedQuadBench());
+
+ for (size_t i = 0; i < tests.size(); i++) {
+ BenchTest* test = tests[i];
+ std::vector<TimeDuration> results;
+ int testsOverThreshold = 0;
+ PROFILER_MARKER(test->ToString());
+ for (size_t j = 0; j < TEST_STEPS; j++) {
+ test->Setup(aCompositor, j);
+
+ TimeStamp start = TimeStamp::Now();
+ IntRect screenRect(aScreenRect.x, aScreenRect.y,
+ aScreenRect.width, aScreenRect.height);
+ aCompositor->BeginFrame(
+ IntRect(screenRect.x, screenRect.y,
+ screenRect.width, screenRect.height),
+ nullptr, aScreenRect, nullptr, nullptr);
+
+ test->DrawFrame(aCompositor, aScreenRect, j);
+
+ aCompositor->EndFrame();
+ results.push_back(TimeStamp::Now() - start);
+
+ if (results[j].ToMilliseconds() > DURATION_THRESHOLD) {
+ testsOverThreshold++;
+ if (testsOverThreshold == THRESHOLD_ABORT_COUNT) {
+ test->Teardown(aCompositor);
+ break;
+ }
+ } else {
+ testsOverThreshold = 0;
+ }
+ test->Teardown(aCompositor);
+ }
+
+ printf_stderr("%s\n", test->ToString());
+ printf_stderr("Run step, Time (ms)\n");
+ for (size_t j = 0; j < results.size(); j++) {
+ printf_stderr("%i,%f\n", j, (float)results[j].ToMilliseconds());
+ }
+ printf_stderr("\n", test->ToString());
+ }
+
+ for (size_t i = 0; i < tests.size(); i++) {
+ delete tests[i];
+ }
+}
+
+void CompositorBench(Compositor* aCompositor, const gfx::IntRect& aScreenRect)
+{
+ static bool sRanBenchmark = false;
+ bool wantBenchmark = gfxPrefs::LayersBenchEnabled();
+ if (wantBenchmark && !sRanBenchmark) {
+ RunCompositorBench(aCompositor, aScreenRect);
+ }
+ sRanBenchmark = wantBenchmark;
+}
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
+
diff --git a/gfx/layers/ipc/CompositorBench.h b/gfx/layers/ipc/CompositorBench.h
new file mode 100644
index 000000000..04c994495
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBench.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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_CompositorBench_h
+#define mozilla_layers_CompositorBench_h
+
+#include "mozilla/gfx/Rect.h" // for Rect
+
+namespace mozilla {
+namespace layers {
+
+class Compositor;
+
+// Uncomment this line to rebuild with compositor bench.
+// #define MOZ_COMPOSITOR_BENCH
+
+#ifdef MOZ_COMPOSITOR_BENCH
+void CompositorBench(Compositor* aCompositor, const gfx::IntRect& aScreenRect);
+#else
+static inline void CompositorBench(Compositor* aCompositor, const gfx::IntRect& aScreenRect) {}
+#endif
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
+
+
diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp
new file mode 100644
index 000000000..f623b10b8
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -0,0 +1,1150 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et 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 "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/CompositorThread.h"
+#include <stddef.h> // for size_t
+#include "ClientLayerManager.h" // for ClientLayerManager
+#include "base/message_loop.h" // for MessageLoop
+#include "base/task.h" // for NewRunnableMethod, etc
+#include "gfxPrefs.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "mozilla/layers/APZChild.h"
+#include "mozilla/layers/IAPZCTreeManager.h"
+#include "mozilla/layers/APZCTreeManagerChild.h"
+#include "mozilla/layers/LayerTransactionChild.h"
+#include "mozilla/layers/PLayerTransactionChild.h"
+#include "mozilla/layers/TextureClient.h"// for TextureClient
+#include "mozilla/layers/TextureClientPool.h"// for TextureClientPool
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/gfx/GPUProcessManager.h"
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "nsAutoPtr.h"
+#include "nsDebug.h" // for NS_RUNTIMEABORT
+#include "nsIObserver.h" // for nsIObserver
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "nsTArray.h" // for nsTArray, nsTArray_Impl
+#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop, etc
+#include "FrameLayerBuilder.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/Unused.h"
+#include "mozilla/DebugOnly.h"
+#if defined(XP_WIN)
+#include "WinUtils.h"
+#endif
+#include "mozilla/widget/CompositorWidget.h"
+#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
+# include "mozilla/widget/CompositorWidgetChild.h"
+#endif
+#include "VsyncSource.h"
+
+using mozilla::layers::LayerTransactionChild;
+using mozilla::dom::TabChildBase;
+using mozilla::Unused;
+using mozilla::gfx::GPUProcessManager;
+
+namespace mozilla {
+namespace layers {
+
+static int sShmemCreationCounter = 0;
+
+static void ResetShmemCounter()
+{
+ sShmemCreationCounter = 0;
+}
+
+static void ShmemAllocated(CompositorBridgeChild* aProtocol)
+{
+ sShmemCreationCounter++;
+ if (sShmemCreationCounter > 256) {
+ aProtocol->SendSyncWithCompositor();
+ ResetShmemCounter();
+ MOZ_PERFORMANCE_WARNING("gfx", "The number of shmem allocations is too damn high!");
+ }
+}
+
+static StaticRefPtr<CompositorBridgeChild> sCompositorBridge;
+
+Atomic<int32_t> KnowsCompositor::sSerialCounter(0);
+
+CompositorBridgeChild::CompositorBridgeChild(LayerManager *aLayerManager)
+ : mLayerManager(aLayerManager)
+ , mCanSend(false)
+ , mFwdTransactionId(0)
+ , mMessageLoop(MessageLoop::current())
+ , mSectionAllocator(nullptr)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
+CompositorBridgeChild::~CompositorBridgeChild()
+{
+ if (mCanSend) {
+ gfxCriticalError() << "CompositorBridgeChild was not deinitialized";
+ }
+}
+
+bool
+CompositorBridgeChild::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+static void DeferredDestroyCompositor(RefPtr<CompositorBridgeParent> aCompositorBridgeParent,
+ RefPtr<CompositorBridgeChild> aCompositorBridgeChild)
+{
+ aCompositorBridgeChild->Close();
+
+ if (sCompositorBridge == aCompositorBridgeChild) {
+ sCompositorBridge = nullptr;
+ }
+}
+
+void
+CompositorBridgeChild::Destroy()
+{
+ // This must not be called from the destructor!
+ mTexturesWaitingRecycled.Clear();
+
+ if (!mCanSend) {
+ return;
+ }
+
+ for (size_t i = 0; i < mTexturePools.Length(); i++) {
+ mTexturePools[i]->Destroy();
+ }
+
+ if (mSectionAllocator) {
+ delete mSectionAllocator;
+ mSectionAllocator = nullptr;
+ }
+
+ // Destroying the layer manager may cause all sorts of things to happen, so
+ // let's make sure there is still a reference to keep this alive whatever
+ // happens.
+ RefPtr<CompositorBridgeChild> selfRef = this;
+
+ if (mLayerManager) {
+ mLayerManager->Destroy();
+ mLayerManager = nullptr;
+ }
+
+ AutoTArray<PLayerTransactionChild*, 16> transactions;
+ ManagedPLayerTransactionChild(transactions);
+ for (int i = transactions.Length() - 1; i >= 0; --i) {
+ RefPtr<LayerTransactionChild> layers =
+ static_cast<LayerTransactionChild*>(transactions[i]);
+ layers->Destroy();
+ }
+
+ const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
+ for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
+ RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
+
+ if (texture) {
+ texture->Destroy();
+ }
+ }
+
+ SendWillClose();
+ mCanSend = false;
+
+ // We no longer care about unexpected shutdowns, in the remote process case.
+ mProcessToken = 0;
+
+ // The call just made to SendWillClose can result in IPC from the
+ // CompositorBridgeParent to the CompositorBridgeChild (e.g. caused by the destruction
+ // of shared memory). We need to ensure this gets processed by the
+ // CompositorBridgeChild before it gets destroyed. It suffices to ensure that
+ // events already in the MessageLoop get processed before the
+ // CompositorBridgeChild is destroyed, so we add a task to the MessageLoop to
+ // handle compositor desctruction.
+
+ // From now on we can't send any message message.
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction(DeferredDestroyCompositor, mCompositorBridgeParent, selfRef));
+}
+
+// static
+void
+CompositorBridgeChild::ShutDown()
+{
+ if (sCompositorBridge) {
+ sCompositorBridge->Destroy();
+ do {
+ NS_ProcessNextEvent(nullptr, true);
+ } while (sCompositorBridge);
+ }
+}
+
+bool
+CompositorBridgeChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId,
+ FrameMetrics& aFrame)
+{
+ SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId);
+ if (data) {
+ data->CopyFrameMetrics(&aFrame);
+ return true;
+ }
+ return false;
+}
+
+/* static */ bool
+CompositorBridgeChild::InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint)
+{
+ // There's only one compositor per child process.
+ MOZ_ASSERT(!sCompositorBridge);
+
+ RefPtr<CompositorBridgeChild> child(new CompositorBridgeChild(nullptr));
+ if (!aEndpoint.Bind(child)) {
+ NS_RUNTIMEABORT("Couldn't Open() Compositor channel.");
+ return false;
+ }
+ child->InitIPDL();
+
+ // We release this ref in DeferredDestroyCompositor.
+ sCompositorBridge = child;
+ return true;
+}
+
+/* static */ bool
+CompositorBridgeChild::ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (RefPtr<CompositorBridgeChild> old = sCompositorBridge.forget()) {
+ // Note that at this point, ActorDestroy may not have been called yet,
+ // meaning mCanSend is still true. In this case we will try to send a
+ // synchronous WillClose message to the parent, and will certainly get
+ // a false result and a MsgDropped processing error. This is okay.
+ old->Destroy();
+ }
+
+ return InitForContent(Move(aEndpoint));
+}
+
+CompositorBridgeParent*
+CompositorBridgeChild::InitSameProcess(widget::CompositorWidget* aWidget,
+ const uint64_t& aLayerTreeId,
+ CSSToLayoutDeviceScale aScale,
+ bool aUseAPZ,
+ bool aUseExternalSurface,
+ const gfx::IntSize& aSurfaceSize)
+{
+ TimeDuration vsyncRate =
+ gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
+
+ mCompositorBridgeParent =
+ new CompositorBridgeParent(aScale, vsyncRate, aUseExternalSurface, aSurfaceSize);
+
+ bool ok = Open(mCompositorBridgeParent->GetIPCChannel(),
+ CompositorThreadHolder::Loop(),
+ ipc::ChildSide);
+ MOZ_RELEASE_ASSERT(ok);
+
+ InitIPDL();
+ mCompositorBridgeParent->InitSameProcess(aWidget, aLayerTreeId, aUseAPZ);
+ return mCompositorBridgeParent;
+}
+
+/* static */ RefPtr<CompositorBridgeChild>
+CompositorBridgeChild::CreateRemote(const uint64_t& aProcessToken,
+ LayerManager* aLayerManager,
+ Endpoint<PCompositorBridgeChild>&& aEndpoint)
+{
+ RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager);
+ if (!aEndpoint.Bind(child)) {
+ return nullptr;
+ }
+ child->InitIPDL();
+ child->mProcessToken = aProcessToken;
+ return child;
+}
+
+void
+CompositorBridgeChild::InitIPDL()
+{
+ mCanSend = true;
+ AddRef();
+}
+
+void
+CompositorBridgeChild::DeallocPCompositorBridgeChild()
+{
+ Release();
+}
+
+/*static*/ CompositorBridgeChild*
+CompositorBridgeChild::Get()
+{
+ // This is only expected to be used in child processes.
+ MOZ_ASSERT(!XRE_IsParentProcess());
+ return sCompositorBridge;
+}
+
+// static
+bool
+CompositorBridgeChild::ChildProcessHasCompositorBridge()
+{
+ return sCompositorBridge != nullptr;
+}
+
+PLayerTransactionChild*
+CompositorBridgeChild::AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints,
+ const uint64_t& aId,
+ TextureFactoryIdentifier*,
+ bool*)
+{
+ LayerTransactionChild* c = new LayerTransactionChild(aId);
+ c->AddIPDLReference();
+ return c;
+}
+
+bool
+CompositorBridgeChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor)
+{
+ uint64_t childId = static_cast<LayerTransactionChild*>(actor)->GetId();
+
+ for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) {
+ nsAutoPtr<SharedFrameMetricsData>& data = iter.Data();
+ if (data->GetLayersId() == childId) {
+ iter.Remove();
+ }
+ }
+ static_cast<LayerTransactionChild*>(actor)->ReleaseIPDLReference();
+ return true;
+}
+
+bool
+CompositorBridgeChild::RecvInvalidateLayers(const uint64_t& aLayersId)
+{
+ if (mLayerManager) {
+ MOZ_ASSERT(aLayersId == 0);
+ FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
+ } else if (aLayersId != 0) {
+ if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) {
+ child->InvalidateLayers();
+ }
+ }
+ return true;
+}
+
+bool
+CompositorBridgeChild::RecvCompositorUpdated(const uint64_t& aLayersId,
+ const TextureFactoryIdentifier& aNewIdentifier)
+{
+ if (mLayerManager) {
+ // This case is handled directly by nsBaseWidget.
+ MOZ_ASSERT(aLayersId == 0);
+ } else if (aLayersId != 0) {
+ if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) {
+ child->CompositorUpdated(aNewIdentifier);
+
+ // If we still get device reset here, something must wrong when creating
+ // d3d11 devices.
+ if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+ gfxCriticalError() << "Unexpected reset device processing when \
+ updating compositor.";
+ }
+ }
+ if (!mCanSend) {
+ return true;
+ }
+ SendAcknowledgeCompositorUpdate(aLayersId);
+ }
+ return true;
+}
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds,
+ const nsTArray<LayoutDeviceIntRect>& aPluginClipRects,
+ const LayoutDeviceIntPoint& aContentOffset,
+ const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
+ nsTArray<LayoutDeviceIntRect>& aResult,
+ LayoutDeviceIntRect& aVisibleBounds,
+ bool& aPluginIsVisible)
+{
+ aPluginIsVisible = true;
+ LayoutDeviceIntRegion contentVisibleRegion;
+ // aPluginClipRects (plugin widget origin) - contains *visible* rects
+ for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) {
+ LayoutDeviceIntRect rect = aPluginClipRects[idx];
+ // shift to content origin
+ rect.MoveBy(aBounds.x, aBounds.y);
+ // accumulate visible rects
+ contentVisibleRegion.OrWith(rect);
+ }
+ // apply layers clip (window origin)
+ LayoutDeviceIntRegion region = aParentLayerVisibleRegion;
+ region.MoveBy(-aContentOffset.x, -aContentOffset.y);
+ contentVisibleRegion.AndWith(region);
+ if (contentVisibleRegion.IsEmpty()) {
+ aPluginIsVisible = false;
+ return;
+ }
+ // shift to plugin widget origin
+ contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y);
+ for (auto iter = contentVisibleRegion.RectIter(); !iter.Done(); iter.Next()) {
+ const LayoutDeviceIntRect& rect = iter.Get();
+ aResult.AppendElement(rect);
+ aVisibleBounds.UnionRect(aVisibleBounds, rect);
+ }
+}
+#endif
+
+bool
+CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
+ const LayoutDeviceIntRegion& aParentLayerVisibleRegion,
+ nsTArray<PluginWindowData>&& aPlugins)
+{
+#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+ NS_NOTREACHED("CompositorBridgeChild::RecvUpdatePluginConfigurations calls "
+ "unexpected on this platform.");
+ return false;
+#else
+ // Now that we are on the main thread, update plugin widget config.
+ // This should happen a little before we paint to the screen assuming
+ // the main thread is running freely.
+ DebugOnly<nsresult> rv;
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Tracks visible plugins we update, so we can hide any plugins we don't.
+ nsTArray<uintptr_t> visiblePluginIds;
+ nsIWidget* parent = nullptr;
+ for (uint32_t pluginsIdx = 0; pluginsIdx < aPlugins.Length(); pluginsIdx++) {
+ nsIWidget* widget =
+ nsIWidget::LookupRegisteredPluginWindow(aPlugins[pluginsIdx].windowId());
+ if (!widget) {
+ NS_WARNING("Unexpected, plugin id not found!");
+ continue;
+ }
+ if (!parent) {
+ parent = widget->GetParent();
+ }
+ bool isVisible = aPlugins[pluginsIdx].visible();
+ if (widget && !widget->Destroyed()) {
+ LayoutDeviceIntRect bounds;
+ LayoutDeviceIntRect visibleBounds;
+ // If the plugin is visible update it's geometry.
+ if (isVisible) {
+ // Set bounds (content origin)
+ bounds = aPlugins[pluginsIdx].bounds();
+ nsTArray<LayoutDeviceIntRect> rectsOut;
+ // This call may change the value of isVisible
+ CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(),
+ aContentOffset,
+ aParentLayerVisibleRegion,
+ rectsOut, visibleBounds, isVisible);
+ // content clipping region (widget origin)
+ rv = widget->SetWindowClipRegion(rectsOut, false);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
+ // This will trigger a browser window paint event for areas uncovered
+ // by a child window move, and will call invalidate on the plugin
+ // parent window which the browser owns. The latter gets picked up in
+ // our OnPaint handler and forwarded over to the plugin process async.
+ rv = widget->Resize(aContentOffset.x + bounds.x,
+ aContentOffset.y + bounds.y,
+ bounds.width, bounds.height, true);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
+ }
+
+ rv = widget->Enable(isVisible);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
+
+ // visible state - updated after clipping, prior to invalidating
+ rv = widget->Show(isVisible);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
+
+ // Handle invalidation, this can be costly, avoid if it is not needed.
+ if (isVisible) {
+ // invalidate region (widget origin)
+#if defined(XP_WIN)
+ // Work around for flash's crummy sandbox. See bug 762948. This call
+ // digs down into the window hirearchy, invalidating regions on
+ // windows owned by other processes.
+ mozilla::widget::WinUtils::InvalidatePluginAsWorkaround(
+ widget, visibleBounds);
+#else
+ rv = widget->Invalidate(visibleBounds);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure");
+#endif
+ visiblePluginIds.AppendElement(aPlugins[pluginsIdx].windowId());
+ }
+ }
+ }
+ // Any plugins we didn't update need to be hidden, as they are
+ // not associated with visible content.
+ nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds);
+ if (!mCanSend) {
+ return true;
+ }
+ SendRemotePluginsReady();
+ return true;
+#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+}
+
+#if defined(XP_WIN)
+static void
+ScheduleSendAllPluginsCaptured(CompositorBridgeChild* aThis, MessageLoop* aLoop)
+{
+ aLoop->PostTask(NewNonOwningRunnableMethod(
+ aThis, &CompositorBridgeChild::SendAllPluginsCaptured));
+}
+#endif
+
+bool
+CompositorBridgeChild::RecvCaptureAllPlugins(const uintptr_t& aParentWidget)
+{
+#if defined(XP_WIN)
+ MOZ_ASSERT(NS_IsMainThread());
+ nsIWidget::CaptureRegisteredPlugins(aParentWidget);
+
+ // Bounce the call to SendAllPluginsCaptured off the ImageBridgeChild loop,
+ // to make sure that the image updates on that thread have been processed.
+ ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
+ NewRunnableFunction(&ScheduleSendAllPluginsCaptured, this,
+ MessageLoop::current()));
+ return true;
+#else
+ MOZ_ASSERT_UNREACHABLE(
+ "CompositorBridgeChild::RecvCaptureAllPlugins calls unexpected.");
+ return false;
+#endif
+}
+
+bool
+CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget)
+{
+#if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+ NS_NOTREACHED("CompositorBridgeChild::RecvHideAllPlugins calls "
+ "unexpected on this platform.");
+ return false;
+#else
+ MOZ_ASSERT(NS_IsMainThread());
+ nsTArray<uintptr_t> list;
+ nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list);
+ if (!mCanSend) {
+ return true;
+ }
+ SendRemotePluginsReady();
+ return true;
+#endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK)
+}
+
+bool
+CompositorBridgeChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId,
+ const TimeStamp& aCompositeStart,
+ const TimeStamp& aCompositeEnd)
+{
+ // Hold a reference to keep texture pools alive. See bug 1387799
+ AutoTArray<RefPtr<TextureClientPool>,2> texturePools = mTexturePools;
+
+ if (mLayerManager) {
+ MOZ_ASSERT(aId == 0);
+ RefPtr<ClientLayerManager> m = mLayerManager->AsClientLayerManager();
+ MOZ_ASSERT(m);
+ m->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
+ } else if (aId != 0) {
+ RefPtr<dom::TabChild> child = dom::TabChild::GetFrom(aId);
+ if (child) {
+ child->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
+ }
+ }
+
+ for (size_t i = 0; i < texturePools.Length(); i++) {
+ texturePools[i]->ReturnDeferredClients();
+ }
+
+ return true;
+}
+
+bool
+CompositorBridgeChild::RecvOverfill(const uint32_t &aOverfill)
+{
+ for (size_t i = 0; i < mOverfillObservers.Length(); i++) {
+ mOverfillObservers[i]->RunOverfillCallback(aOverfill);
+ }
+ mOverfillObservers.Clear();
+ return true;
+}
+
+void
+CompositorBridgeChild::AddOverfillObserver(ClientLayerManager* aLayerManager)
+{
+ MOZ_ASSERT(aLayerManager);
+ mOverfillObservers.AppendElement(aLayerManager);
+}
+
+bool
+CompositorBridgeChild::RecvClearCachedResources(const uint64_t& aId)
+{
+ dom::TabChild* child = dom::TabChild::GetFrom(aId);
+ if (child) {
+ child->ClearCachedResources();
+ }
+ return true;
+}
+
+void
+CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+ if (aWhy == AbnormalShutdown) {
+ // If the parent side runs into a problem then the actor will be destroyed.
+ // There is nothing we can do in the child side, here sets mCanSend as false.
+ gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown";
+ }
+
+ mCanSend = false;
+
+ if (mProcessToken && XRE_IsParentProcess()) {
+ GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
+ }
+}
+
+bool
+CompositorBridgeChild::RecvSharedCompositorFrameMetrics(
+ const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
+ const CrossProcessMutexHandle& handle,
+ const uint64_t& aLayersId,
+ const uint32_t& aAPZCId)
+{
+ SharedFrameMetricsData* data = new SharedFrameMetricsData(
+ metrics, handle, aLayersId, aAPZCId);
+ mFrameMetricsTable.Put(data->GetViewID(), data);
+ return true;
+}
+
+bool
+CompositorBridgeChild::RecvReleaseSharedCompositorFrameMetrics(
+ const ViewID& aId,
+ const uint32_t& aAPZCId)
+{
+ SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId);
+ // The SharedFrameMetricsData may have been removed previously if
+ // a SharedFrameMetricsData with the same ViewID but later APZCId had
+ // been store and over wrote it.
+ if (data && (data->GetAPZCId() == aAPZCId)) {
+ mFrameMetricsTable.Remove(aId);
+ }
+ return true;
+}
+
+CompositorBridgeChild::SharedFrameMetricsData::SharedFrameMetricsData(
+ const ipc::SharedMemoryBasic::Handle& metrics,
+ const CrossProcessMutexHandle& handle,
+ const uint64_t& aLayersId,
+ const uint32_t& aAPZCId)
+ : mMutex(nullptr)
+ , mLayersId(aLayersId)
+ , mAPZCId(aAPZCId)
+{
+ mBuffer = new ipc::SharedMemoryBasic;
+ mBuffer->SetHandle(metrics);
+ mBuffer->Map(sizeof(FrameMetrics));
+ mMutex = new CrossProcessMutex(handle);
+ MOZ_COUNT_CTOR(SharedFrameMetricsData);
+}
+
+CompositorBridgeChild::SharedFrameMetricsData::~SharedFrameMetricsData()
+{
+ // When the hash table deletes the class, delete
+ // the shared memory and mutex.
+ delete mMutex;
+ mBuffer = nullptr;
+ MOZ_COUNT_DTOR(SharedFrameMetricsData);
+}
+
+void
+CompositorBridgeChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame)
+{
+ FrameMetrics* frame = static_cast<FrameMetrics*>(mBuffer->memory());
+ MOZ_ASSERT(frame);
+ mMutex->Lock();
+ *aFrame = *frame;
+ mMutex->Unlock();
+}
+
+FrameMetrics::ViewID
+CompositorBridgeChild::SharedFrameMetricsData::GetViewID()
+{
+ FrameMetrics* frame = static_cast<FrameMetrics*>(mBuffer->memory());
+ MOZ_ASSERT(frame);
+ // Not locking to read of mScrollId since it should not change after being
+ // initially set.
+ return frame->GetScrollId();
+}
+
+uint64_t
+CompositorBridgeChild::SharedFrameMetricsData::GetLayersId() const
+{
+ return mLayersId;
+}
+
+uint32_t
+CompositorBridgeChild::SharedFrameMetricsData::GetAPZCId()
+{
+ return mAPZCId;
+}
+
+
+bool
+CompositorBridgeChild::RecvRemotePaintIsReady()
+{
+ // Used on the content thread, this bounces the message to the
+ // TabParent (via the TabChild) if the notification was previously requested.
+ // XPCOM gives a soup of compiler errors when trying to do_QueryReference
+ // so I'm using static_cast<>
+ MOZ_LAYERS_LOG(("[RemoteGfx] CompositorBridgeChild received RemotePaintIsReady"));
+ RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild));
+ if (!iTabChildBase) {
+ MOZ_LAYERS_LOG(("[RemoteGfx] Note: TabChild was released before RemotePaintIsReady. "
+ "MozAfterRemotePaint will not be sent to listener."));
+ return true;
+ }
+ TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get());
+ TabChild* tabChild = static_cast<TabChild*>(tabChildBase);
+ MOZ_ASSERT(tabChild);
+ Unused << tabChild->SendRemotePaintIsReady();
+ mWeakTabChild = nullptr;
+ return true;
+}
+
+
+void
+CompositorBridgeChild::RequestNotifyAfterRemotePaint(TabChild* aTabChild)
+{
+ MOZ_ASSERT(aTabChild, "NULL TabChild not allowed in CompositorBridgeChild::RequestNotifyAfterRemotePaint");
+ mWeakTabChild = do_GetWeakReference( static_cast<dom::TabChildBase*>(aTabChild) );
+ if (!mCanSend) {
+ return;
+ }
+ Unused << SendRequestNotifyAfterRemotePaint();
+}
+
+void
+CompositorBridgeChild::CancelNotifyAfterRemotePaint(TabChild* aTabChild)
+{
+ RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild));
+ if (!iTabChildBase) {
+ return;
+ }
+ TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get());
+ TabChild* tabChild = static_cast<TabChild*>(tabChildBase);
+ if (tabChild == aTabChild) {
+ mWeakTabChild = nullptr;
+ }
+}
+
+bool
+CompositorBridgeChild::SendWillClose()
+{
+ MOZ_RELEASE_ASSERT(mCanSend);
+ return PCompositorBridgeChild::SendWillClose();
+}
+
+bool
+CompositorBridgeChild::SendPause()
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendPause();
+}
+
+bool
+CompositorBridgeChild::SendResume()
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendResume();
+}
+
+bool
+CompositorBridgeChild::SendNotifyChildCreated(const uint64_t& id)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendNotifyChildCreated(id);
+}
+
+bool
+CompositorBridgeChild::SendAdoptChild(const uint64_t& id)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendAdoptChild(id);
+}
+
+bool
+CompositorBridgeChild::SendMakeSnapshot(const SurfaceDescriptor& inSnapshot, const gfx::IntRect& dirtyRect)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendMakeSnapshot(inSnapshot, dirtyRect);
+}
+
+bool
+CompositorBridgeChild::SendFlushRendering()
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendFlushRendering();
+}
+
+bool
+CompositorBridgeChild::SendStartFrameTimeRecording(const int32_t& bufferSize, uint32_t* startIndex)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendStartFrameTimeRecording(bufferSize, startIndex);
+}
+
+bool
+CompositorBridgeChild::SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendStopFrameTimeRecording(startIndex, intervals);
+}
+
+bool
+CompositorBridgeChild::SendNotifyRegionInvalidated(const nsIntRegion& region)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendNotifyRegionInvalidated(region);
+}
+
+bool
+CompositorBridgeChild::SendRequestNotifyAfterRemotePaint()
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendRequestNotifyAfterRemotePaint();
+}
+
+bool
+CompositorBridgeChild::SendClearApproximatelyVisibleRegions(uint64_t aLayersId,
+ uint32_t aPresShellId)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendClearApproximatelyVisibleRegions(aLayersId,
+ aPresShellId);
+}
+
+bool
+CompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+ const CSSIntRegion& aRegion)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(aGuid, aRegion);
+}
+
+bool
+CompositorBridgeChild::SendAllPluginsCaptured()
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::SendAllPluginsCaptured();
+}
+
+PTextureChild*
+CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+ const LayersBackend&,
+ const TextureFlags&,
+ const uint64_t&,
+ const uint64_t& aSerial)
+{
+ return TextureClient::CreateIPDLActor();
+}
+
+bool
+CompositorBridgeChild::DeallocPTextureChild(PTextureChild* actor)
+{
+ return TextureClient::DestroyIPDLActor(actor);
+}
+
+bool
+CompositorBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
+{
+ for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
+ const AsyncParentMessageData& message = aMessages[i];
+
+ switch (message.type()) {
+ case AsyncParentMessageData::TOpNotifyNotUsed: {
+ const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
+ NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
+ break;
+ }
+ default:
+ NS_ERROR("unknown AsyncParentMessageData type");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+CompositorBridgeChild::RecvObserveLayerUpdate(const uint64_t& aLayersId,
+ const uint64_t& aEpoch,
+ const bool& aActive)
+{
+ // This message is sent via the window compositor, not the tab compositor -
+ // however it still has a layers id.
+ MOZ_ASSERT(aLayersId);
+ MOZ_ASSERT(XRE_IsParentProcess());
+
+ if (RefPtr<dom::TabParent> tab = dom::TabParent::GetTabParentFromLayersId(aLayersId)) {
+ tab->LayerTreeUpdate(aEpoch, aActive);
+ }
+ return true;
+}
+
+void
+CompositorBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
+{
+ if (!aClient) {
+ return;
+ }
+
+ if (!(aClient->GetFlags() & TextureFlags::RECYCLE)) {
+ return;
+ }
+
+ aClient->SetLastFwdTransactionId(GetFwdTransactionId());
+ mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
+}
+
+void
+CompositorBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
+{
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ if (aFwdTransactionId < client->GetLastFwdTransactionId()) {
+ // Released on host side, but client already requested newer use texture.
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+void
+CompositorBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
+{
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+TextureClientPool*
+CompositorBridgeChild::GetTexturePool(KnowsCompositor* aAllocator,
+ SurfaceFormat aFormat,
+ TextureFlags aFlags)
+{
+ for (size_t i = 0; i < mTexturePools.Length(); i++) {
+ if (mTexturePools[i]->GetBackend() == aAllocator->GetCompositorBackendType() &&
+ mTexturePools[i]->GetMaxTextureSize() == aAllocator->GetMaxTextureSize() &&
+ mTexturePools[i]->GetFormat() == aFormat &&
+ mTexturePools[i]->GetFlags() == aFlags) {
+ return mTexturePools[i];
+ }
+ }
+
+ mTexturePools.AppendElement(
+ new TextureClientPool(aAllocator->GetCompositorBackendType(),
+ aAllocator->GetMaxTextureSize(),
+ aFormat,
+ gfx::gfxVars::TileSize(),
+ aFlags,
+ gfxPrefs::LayersTilePoolShrinkTimeout(),
+ gfxPrefs::LayersTilePoolClearTimeout(),
+ gfxPrefs::LayersTileInitialPoolSize(),
+ gfxPrefs::LayersTilePoolUnusedSize(),
+ this));
+
+ return mTexturePools.LastElement();
+}
+
+void
+CompositorBridgeChild::HandleMemoryPressure()
+{
+ for (size_t i = 0; i < mTexturePools.Length(); i++) {
+ mTexturePools[i]->Clear();
+ }
+}
+
+void
+CompositorBridgeChild::ClearTexturePool()
+{
+ for (size_t i = 0; i < mTexturePools.Length(); i++) {
+ mTexturePools[i]->Clear();
+ }
+}
+
+FixedSizeSmallShmemSectionAllocator*
+CompositorBridgeChild::GetTileLockAllocator()
+{
+ MOZ_ASSERT(IPCOpen());
+ if (!IPCOpen()) {
+ return nullptr;
+ }
+
+ if (!mSectionAllocator) {
+ mSectionAllocator = new FixedSizeSmallShmemSectionAllocator(this);
+ }
+ return mSectionAllocator;
+}
+
+
+PTextureChild*
+CompositorBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial)
+{
+ return PCompositorBridgeChild::SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial);
+}
+
+bool
+CompositorBridgeChild::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ ShmemAllocated(this);
+ return PCompositorBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+bool
+CompositorBridgeChild::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ ShmemAllocated(this);
+ return PCompositorBridgeChild::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+CompositorBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
+{
+ if (!mCanSend) {
+ return false;
+ }
+ return PCompositorBridgeChild::DeallocShmem(aShmem);
+}
+
+widget::PCompositorWidgetChild*
+CompositorBridgeChild::AllocPCompositorWidgetChild(const CompositorWidgetInitData& aInitData)
+{
+ // We send the constructor manually.
+ MOZ_CRASH("Should not be called");
+ return nullptr;
+}
+
+bool
+CompositorBridgeChild::DeallocPCompositorWidgetChild(PCompositorWidgetChild* aActor)
+{
+#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
+ delete aActor;
+ return true;
+#else
+ return false;
+#endif
+}
+
+RefPtr<IAPZCTreeManager>
+CompositorBridgeChild::GetAPZCTreeManager(uint64_t aLayerTreeId)
+{
+ bool apzEnabled = false;
+ Unused << SendAsyncPanZoomEnabled(aLayerTreeId, &apzEnabled);
+
+ if (!apzEnabled) {
+ return nullptr;
+ }
+
+ PAPZCTreeManagerChild* child = SendPAPZCTreeManagerConstructor(aLayerTreeId);
+ if (!child) {
+ return nullptr;
+ }
+ APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(child);
+
+ return RefPtr<IAPZCTreeManager>(parent);
+}
+
+PAPZCTreeManagerChild*
+CompositorBridgeChild::AllocPAPZCTreeManagerChild(const uint64_t& aLayersId)
+{
+ APZCTreeManagerChild* child = new APZCTreeManagerChild();
+ child->AddRef();
+ return child;
+}
+
+PAPZChild*
+CompositorBridgeChild::AllocPAPZChild(const uint64_t& aLayersId)
+{
+ // We send the constructor manually.
+ MOZ_CRASH("Should not be called");
+ return nullptr;
+}
+
+bool
+CompositorBridgeChild::DeallocPAPZChild(PAPZChild* aActor)
+{
+ delete aActor;
+ return true;
+}
+
+bool
+CompositorBridgeChild::DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor)
+{
+ APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(aActor);
+ parent->Release();
+ return true;
+}
+
+void
+CompositorBridgeChild::ProcessingError(Result aCode, const char* aReason)
+{
+ if (aCode != MsgDropped) {
+ gfxDevCrash(gfx::LogReason::ProcessingError) << "Processing error in CompositorBridgeChild: " << int(aCode);
+ }
+}
+
+void
+CompositorBridgeChild::WillEndTransaction()
+{
+ ResetShmemCounter();
+}
+
+void
+CompositorBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+{
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
+}
+
+} // namespace layers
+} // namespace mozilla
+
diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h
new file mode 100644
index 000000000..60d1a146d
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -0,0 +1,333 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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_CompositorBridgeChild_h
+#define mozilla_layers_CompositorBridgeChild_h
+
+#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS
+#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/PCompositorBridgeChild.h"
+#include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
+#include "nsClassHashtable.h" // for nsClassHashtable
+#include "nsCOMPtr.h" // for nsCOMPtr
+#include "nsHashKeys.h" // for nsUint64HashKey
+#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+
+namespace dom {
+class TabChild;
+} // namespace dom
+
+namespace widget {
+class CompositorWidget;
+} // namespace widget
+
+namespace layers {
+
+using mozilla::dom::TabChild;
+
+class IAPZCTreeManager;
+class APZCTreeManagerChild;
+class ClientLayerManager;
+class CompositorBridgeParent;
+class TextureClient;
+class TextureClientPool;
+struct FrameMetrics;
+
+class CompositorBridgeChild final : public PCompositorBridgeChild,
+ public TextureForwarder
+{
+ typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
+
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorBridgeChild, override);
+
+ explicit CompositorBridgeChild(LayerManager *aLayerManager);
+
+ void Destroy();
+
+ /**
+ * Lookup the FrameMetrics shared by the compositor process with the
+ * associated FrameMetrics::ViewID. The returned FrameMetrics is used
+ * in progressive paint calculations.
+ */
+ bool LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, FrameMetrics&);
+
+ /**
+ * Initialize the singleton compositor bridge for a content process.
+ */
+ static bool InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint);
+ static bool ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint);
+
+ static RefPtr<CompositorBridgeChild> CreateRemote(
+ const uint64_t& aProcessToken,
+ LayerManager* aLayerManager,
+ Endpoint<PCompositorBridgeChild>&& aEndpoint);
+
+ /**
+ * Initialize the CompositorBridgeChild, create CompositorBridgeParent, and
+ * open a same-process connection.
+ */
+ CompositorBridgeParent* InitSameProcess(
+ widget::CompositorWidget* aWidget,
+ const uint64_t& aLayerTreeId,
+ CSSToLayoutDeviceScale aScale,
+ bool aUseAPZ,
+ bool aUseExternalSurface,
+ const gfx::IntSize& aSurfaceSize);
+
+ static CompositorBridgeChild* Get();
+
+ static bool ChildProcessHasCompositorBridge();
+
+ void AddOverfillObserver(ClientLayerManager* aLayerManager);
+
+ virtual bool
+ RecvClearCachedResources(const uint64_t& id) override;
+
+ virtual bool
+ RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId,
+ const TimeStamp& aCompositeStart,
+ const TimeStamp& aCompositeEnd) override;
+
+ virtual bool
+ RecvInvalidateLayers(const uint64_t& aLayersId) override;
+
+ virtual bool
+ RecvCompositorUpdated(const uint64_t& aLayersId,
+ const TextureFactoryIdentifier& aNewIdentifier) override;
+
+ virtual bool
+ RecvOverfill(const uint32_t &aOverfill) override;
+
+ virtual bool
+ RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset,
+ const LayoutDeviceIntRegion& aVisibleRegion,
+ nsTArray<PluginWindowData>&& aPlugins) override;
+
+ virtual bool
+ RecvCaptureAllPlugins(const uintptr_t& aParentWidget) override;
+
+ virtual bool
+ RecvHideAllPlugins(const uintptr_t& aParentWidget) override;
+
+ virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aId,
+ const uint64_t& aSerial) override;
+
+ virtual bool DeallocPTextureChild(PTextureChild* actor) override;
+
+ virtual bool
+ RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
+ virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial) override;
+
+ virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+
+ /**
+ * Request that the parent tell us when graphics are ready on GPU.
+ * When we get that message, we bounce it to the TabParent via
+ * the TabChild
+ * @param tabChild The object to bounce the note to. Non-NULL.
+ */
+ void RequestNotifyAfterRemotePaint(TabChild* aTabChild);
+
+ void CancelNotifyAfterRemotePaint(TabChild* aTabChild);
+
+ // Beware that these methods don't override their super-class equivalent (which
+ // are not virtual), they just overload them.
+ // All of these Send* methods just add a sanity check (that it is not too late
+ // send a message) and forward the call to the super-class's equivalent method.
+ // This means that it is correct to call directly the super-class methods, but
+ // you won't get the extra safety provided here.
+ bool SendWillClose();
+ bool SendPause();
+ bool SendResume();
+ bool SendNotifyChildCreated(const uint64_t& id);
+ bool SendAdoptChild(const uint64_t& id);
+ bool SendMakeSnapshot(const SurfaceDescriptor& inSnapshot, const gfx::IntRect& dirtyRect);
+ bool SendFlushRendering();
+ bool SendGetTileSize(int32_t* tileWidth, int32_t* tileHeight);
+ bool SendStartFrameTimeRecording(const int32_t& bufferSize, uint32_t* startIndex);
+ bool SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals);
+ bool SendNotifyRegionInvalidated(const nsIntRegion& region);
+ bool SendRequestNotifyAfterRemotePaint();
+ bool SendClearApproximatelyVisibleRegions(uint64_t aLayersId, uint32_t aPresShellId);
+ bool SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+ const mozilla::CSSIntRegion& aRegion);
+ bool SendAllPluginsCaptured();
+ bool IsSameProcess() const override;
+
+ virtual bool IPCOpen() const override { return mCanSend; }
+
+ static void ShutDown();
+
+ void UpdateFwdTransactionId() { ++mFwdTransactionId; }
+ uint64_t GetFwdTransactionId() { return mFwdTransactionId; }
+
+ /**
+ * Hold TextureClient ref until end of usage on host side if TextureFlags::RECYCLE is set.
+ * Host side's usage is checked via CompositableRef.
+ */
+ void HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient);
+
+ /**
+ * Notify id of Texture When host side end its use. Transaction id is used to
+ * make sure if there is no newer usage.
+ */
+ void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
+
+ virtual void CancelWaitForRecycle(uint64_t aTextureId) override;
+
+ TextureClientPool* GetTexturePool(KnowsCompositor* aAllocator,
+ gfx::SurfaceFormat aFormat,
+ TextureFlags aFlags);
+ void ClearTexturePool();
+
+ virtual FixedSizeSmallShmemSectionAllocator* GetTileLockAllocator() override;
+
+ void HandleMemoryPressure();
+
+ virtual MessageLoop* GetMessageLoop() const override { return mMessageLoop; }
+
+ virtual base::ProcessId GetParentPid() const override { return OtherPid(); }
+
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) override;
+ virtual bool AllocShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) override;
+ virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
+ PCompositorWidgetChild* AllocPCompositorWidgetChild(const CompositorWidgetInitData& aInitData) override;
+ bool DeallocPCompositorWidgetChild(PCompositorWidgetChild* aActor) override;
+
+ RefPtr<IAPZCTreeManager> GetAPZCTreeManager(uint64_t aLayerTreeId);
+
+ PAPZCTreeManagerChild* AllocPAPZCTreeManagerChild(const uint64_t& aLayersId) override;
+ bool DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor) override;
+
+ PAPZChild* AllocPAPZChild(const uint64_t& aLayersId) override;
+ bool DeallocPAPZChild(PAPZChild* aActor) override;
+
+ void ProcessingError(Result aCode, const char* aReason) override;
+
+ void WillEndTransaction();
+
+private:
+ // Private destructor, to discourage deletion outside of Release():
+ virtual ~CompositorBridgeChild();
+
+ void InitIPDL();
+ void DeallocPCompositorBridgeChild() override;
+
+ virtual PLayerTransactionChild*
+ AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints,
+ const uint64_t& aId,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ bool* aSuccess) override;
+
+ virtual bool DeallocPLayerTransactionChild(PLayerTransactionChild *aChild) override;
+
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ virtual bool RecvSharedCompositorFrameMetrics(const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
+ const CrossProcessMutexHandle& handle,
+ const uint64_t& aLayersId,
+ const uint32_t& aAPZCId) override;
+
+ virtual bool RecvReleaseSharedCompositorFrameMetrics(const ViewID& aId,
+ const uint32_t& aAPZCId) override;
+
+ virtual bool
+ RecvRemotePaintIsReady() override;
+
+ bool RecvObserveLayerUpdate(const uint64_t& aLayersId,
+ const uint64_t& aEpoch,
+ const bool& aActive) override;
+
+ // Class used to store the shared FrameMetrics, mutex, and APZCId in a hash table
+ class SharedFrameMetricsData {
+ public:
+ SharedFrameMetricsData(
+ const mozilla::ipc::SharedMemoryBasic::Handle& metrics,
+ const CrossProcessMutexHandle& handle,
+ const uint64_t& aLayersId,
+ const uint32_t& aAPZCId);
+
+ ~SharedFrameMetricsData();
+
+ void CopyFrameMetrics(FrameMetrics* aFrame);
+ FrameMetrics::ViewID GetViewID();
+ uint64_t GetLayersId() const;
+ uint32_t GetAPZCId();
+
+ private:
+ // Pointer to the class that allows access to the shared memory that contains
+ // the shared FrameMetrics
+ RefPtr<mozilla::ipc::SharedMemoryBasic> mBuffer;
+ CrossProcessMutex* mMutex;
+ uint64_t mLayersId;
+ // Unique ID of the APZC that is sharing the FrameMetrics
+ uint32_t mAPZCId;
+ };
+
+ RefPtr<LayerManager> mLayerManager;
+ // When not multi-process, hold a reference to the CompositorBridgeParent to keep it
+ // alive. This reference should be null in multi-process.
+ RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
+
+ // The ViewID of the FrameMetrics is used as the key for this hash table.
+ // While this should be safe to use since the ViewID is unique
+ nsClassHashtable<nsUint64HashKey, SharedFrameMetricsData> mFrameMetricsTable;
+
+ // Weakly hold the TabChild that made a request to be alerted when
+ // the transaction has been received.
+ nsWeakPtr mWeakTabChild; // type is TabChild
+
+ DISALLOW_EVIL_CONSTRUCTORS(CompositorBridgeChild);
+
+ // When we receive overfill numbers, notify these client layer managers
+ AutoTArray<ClientLayerManager*,0> mOverfillObservers;
+
+ // True until the beginning of the two-step shutdown sequence of this actor.
+ bool mCanSend;
+
+ /**
+ * Transaction id of ShadowLayerForwarder.
+ * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call.
+ */
+ uint64_t mFwdTransactionId;
+
+ /**
+ * Hold TextureClients refs until end of their usages on host side.
+ * It defer calling of TextureClient recycle callback.
+ */
+ nsDataHashtable<nsUint64HashKey, RefPtr<TextureClient> > mTexturesWaitingRecycled;
+
+ MessageLoop* mMessageLoop;
+
+ AutoTArray<RefPtr<TextureClientPool>,2> mTexturePools;
+
+ uint64_t mProcessToken;
+
+ FixedSizeSmallShmemSectionAllocator* mSectionAllocator;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_CompositorBrigedChild_h
diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp
new file mode 100644
index 000000000..6728e8841
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -0,0 +1,2441 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et 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 "mozilla/layers/CompositorBridgeParent.h"
+#include <stdio.h> // for fprintf, stdout
+#include <stdint.h> // for uint64_t
+#include <map> // for _Rb_tree_iterator, etc
+#include <utility> // for pair
+#include "LayerTransactionParent.h" // for LayerTransactionParent
+#include "RenderTrace.h" // for RenderTraceLayers
+#include "base/message_loop.h" // for MessageLoop
+#include "base/process.h" // for ProcessId
+#include "base/task.h" // for CancelableTask, etc
+#include "base/thread.h" // for Thread
+#include "gfxContext.h" // for gfxContext
+#include "gfxPlatform.h" // for gfxPlatform
+#include "TreeTraversal.h" // for ForEachNode
+#ifdef MOZ_WIDGET_GTK
+#include "gfxPlatformGtk.h" // for gfxPlatform
+#endif
+#include "gfxPrefs.h" // for gfxPrefs
+#include "mozilla/AutoRestore.h" // for AutoRestore
+#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
+#include "mozilla/DebugOnly.h" // for DebugOnly
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/gfx/2D.h" // for DrawTarget
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/gfx/Rect.h" // for IntSize
+#include "VRManager.h" // for VRManager
+#include "mozilla/ipc/Transport.h" // for Transport
+#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
+#include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
+#include "mozilla/layers/APZThreadUtils.h" // for APZCTreeManager
+#include "mozilla/layers/AsyncCompositionManager.h"
+#include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
+#include "mozilla/layers/Compositor.h" // for Compositor
+#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/CrossProcessCompositorBridgeParent.h"
+#include "mozilla/layers/FrameUniformityData.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/LayerTreeOwnerTracker.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/PLayerTransactionParent.h"
+#include "mozilla/layers/RemoteContentController.h"
+#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "mozilla/Telemetry.h"
+#ifdef MOZ_WIDGET_GTK
+#include "basic/X11BasicCompositor.h" // for X11BasicCompositor
+#endif
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsDebug.h" // for NS_ASSERTION, etc
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "nsIWidget.h" // for nsIWidget
+#include "nsTArray.h" // for nsTArray
+#include "nsThreadUtils.h" // for NS_IsMainThread
+#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
+#ifdef XP_WIN
+#include "mozilla/layers/CompositorD3D11.h"
+#include "mozilla/layers/CompositorD3D9.h"
+#endif
+#include "GeckoProfiler.h"
+#include "mozilla/ipc/ProtocolTypes.h"
+#include "mozilla/Unused.h"
+#include "mozilla/Hal.h"
+#include "mozilla/HalTypes.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Telemetry.h"
+#ifdef MOZ_ENABLE_PROFILER_SPS
+#include "ProfilerMarkers.h"
+#endif
+#include "mozilla/VsyncDispatcher.h"
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+#include "VsyncSource.h"
+#endif
+#include "mozilla/widget/CompositorWidget.h"
+#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
+# include "mozilla/widget/CompositorWidgetParent.h"
+#endif
+
+#include "LayerScope.h"
+
+namespace mozilla {
+
+namespace layers {
+
+using namespace mozilla::ipc;
+using namespace mozilla::gfx;
+using namespace std;
+
+using base::ProcessId;
+using base::Thread;
+
+ProcessId
+CompositorBridgeParentBase::GetChildProcessId()
+{
+ return OtherPid();
+}
+
+void
+CompositorBridgeParentBase::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
+{
+ RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
+ if (!texture) {
+ return;
+ }
+
+ if (!(texture->GetFlags() & TextureFlags::RECYCLE)) {
+ return;
+ }
+
+ uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
+ mPendingAsyncMessage.push_back(
+ OpNotifyNotUsed(textureId, aTransactionId));
+}
+
+void
+CompositorBridgeParentBase::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
+{
+ Unused << SendParentAsyncMessages(aMessage);
+}
+
+bool
+CompositorBridgeParentBase::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+CompositorBridgeParentBase::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+void
+CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem)
+{
+ PCompositorBridgeParent::DeallocShmem(aShmem);
+}
+
+base::ProcessId
+CompositorBridgeParentBase::RemotePid()
+{
+ return OtherPid();
+}
+
+bool
+CompositorBridgeParentBase::StartSharingMetrics(ipc::SharedMemoryBasic::Handle aHandle,
+ CrossProcessMutexHandle aMutexHandle,
+ uint64_t aLayersId,
+ uint32_t aApzcId)
+{
+ return PCompositorBridgeParent::SendSharedCompositorFrameMetrics(
+ aHandle, aMutexHandle, aLayersId, aApzcId);
+}
+
+bool
+CompositorBridgeParentBase::StopSharingMetrics(FrameMetrics::ViewID aScrollId,
+ uint32_t aApzcId)
+{
+ return PCompositorBridgeParent::SendReleaseSharedCompositorFrameMetrics(
+ aScrollId, aApzcId);
+}
+
+CompositorBridgeParent::LayerTreeState::LayerTreeState()
+ : mApzcTreeManagerParent(nullptr)
+ , mParent(nullptr)
+ , mLayerManager(nullptr)
+ , mCrossProcessParent(nullptr)
+ , mLayerTree(nullptr)
+ , mUpdatedPluginDataAvailable(false)
+ , mPendingCompositorUpdates(0)
+{
+}
+
+CompositorBridgeParent::LayerTreeState::~LayerTreeState()
+{
+ if (mController) {
+ mController->Destroy();
+ }
+}
+
+typedef map<uint64_t, CompositorBridgeParent::LayerTreeState> LayerTreeMap;
+static LayerTreeMap sIndirectLayerTrees;
+static StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
+
+static void EnsureLayerTreeMapReady()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (!sIndirectLayerTreesLock) {
+ sIndirectLayerTreesLock = new Monitor("IndirectLayerTree");
+ mozilla::ClearOnShutdown(&sIndirectLayerTreesLock);
+ }
+}
+
+template <typename Lambda>
+inline void
+CompositorBridgeParent::ForEachIndirectLayerTree(const Lambda& aCallback)
+{
+ sIndirectLayerTreesLock->AssertCurrentThreadOwns();
+ for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end(); it++) {
+ LayerTreeState* state = &it->second;
+ if (state->mParent == this) {
+ aCallback(state, it->first);
+ }
+ }
+}
+
+/**
+ * A global map referencing each compositor by ID.
+ *
+ * This map is used by the ImageBridge protocol to trigger
+ * compositions without having to keep references to the
+ * compositor
+ */
+typedef map<uint64_t,CompositorBridgeParent*> CompositorMap;
+static StaticAutoPtr<CompositorMap> sCompositorMap;
+
+void
+CompositorBridgeParent::Setup()
+{
+ EnsureLayerTreeMapReady();
+
+ MOZ_ASSERT(!sCompositorMap);
+ sCompositorMap = new CompositorMap;
+}
+
+void
+CompositorBridgeParent::Shutdown()
+{
+ MOZ_ASSERT(sCompositorMap);
+ MOZ_ASSERT(sCompositorMap->empty());
+ sCompositorMap = nullptr;
+}
+
+void
+CompositorBridgeParent::FinishShutdown()
+{
+ // TODO: this should be empty by now...
+ sIndirectLayerTrees.clear();
+}
+
+static void SetThreadPriority()
+{
+ hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
+}
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+static int32_t
+CalculateCompositionFrameRate()
+{
+ // Used when layout.frame_rate is -1. Needs to be kept in sync with
+ // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
+ // TODO: This should actually return the vsync rate.
+ const int32_t defaultFrameRate = 60;
+ int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate();
+ if (compositionFrameRatePref < 0) {
+ // Use the same frame rate for composition as for layout.
+ int32_t layoutFrameRatePref = gfxPrefs::LayoutFrameRate();
+ if (layoutFrameRatePref < 0) {
+ // TODO: The main thread frame scheduling code consults the actual
+ // monitor refresh rate in this case. We should do the same.
+ return defaultFrameRate;
+ }
+ return layoutFrameRatePref;
+ }
+ return compositionFrameRatePref;
+}
+#endif
+
+CompositorVsyncScheduler::Observer::Observer(CompositorVsyncScheduler* aOwner)
+ : mMutex("CompositorVsyncScheduler.Observer.Mutex")
+ , mOwner(aOwner)
+{
+}
+
+CompositorVsyncScheduler::Observer::~Observer()
+{
+ MOZ_ASSERT(!mOwner);
+}
+
+bool
+CompositorVsyncScheduler::Observer::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+ MutexAutoLock lock(mMutex);
+ if (!mOwner) {
+ return false;
+ }
+ return mOwner->NotifyVsync(aVsyncTimestamp);
+}
+
+void
+CompositorVsyncScheduler::Observer::Destroy()
+{
+ MutexAutoLock lock(mMutex);
+ mOwner = nullptr;
+}
+
+CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent,
+ widget::CompositorWidget* aWidget)
+ : mCompositorBridgeParent(aCompositorBridgeParent)
+ , mLastCompose(TimeStamp::Now())
+ , mIsObservingVsync(false)
+ , mNeedsComposite(0)
+ , mVsyncNotificationsSkipped(0)
+ , mWidget(aWidget)
+ , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
+ , mCurrentCompositeTask(nullptr)
+ , mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
+ , mSetNeedsCompositeTask(nullptr)
+{
+ MOZ_ASSERT(NS_IsMainThread() || XRE_GetProcessType() == GeckoProcessType_GPU);
+ mVsyncObserver = new Observer(this);
+
+ // mAsapScheduling is set on the main thread during init,
+ // but is only accessed after on the compositor thread.
+ mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 ||
+ gfxPlatform::IsInLayoutAsapMode();
+}
+
+CompositorVsyncScheduler::~CompositorVsyncScheduler()
+{
+ MOZ_ASSERT(!mIsObservingVsync);
+ MOZ_ASSERT(!mVsyncObserver);
+ // The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
+ mCompositorBridgeParent = nullptr;
+}
+
+void
+CompositorVsyncScheduler::Destroy()
+{
+ if (!mVsyncObserver) {
+ // Destroy was already called on this object.
+ return;
+ }
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ UnobserveVsync();
+ mVsyncObserver->Destroy();
+ mVsyncObserver = nullptr;
+
+ CancelCurrentSetNeedsCompositeTask();
+ CancelCurrentCompositeTask();
+}
+
+void
+CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp)
+{
+ // can be called from the compositor or vsync thread
+ MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
+ if (mCurrentCompositeTask == nullptr && CompositorThreadHolder::Loop()) {
+ RefPtr<CancelableRunnable> task =
+ NewCancelableRunnableMethod<TimeStamp>(this, &CompositorVsyncScheduler::Composite,
+ aCompositeTimestamp);
+ mCurrentCompositeTask = task;
+ ScheduleTask(task.forget(), 0);
+ }
+}
+
+void
+CompositorVsyncScheduler::ScheduleComposition()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ if (mAsapScheduling) {
+ // Used only for performance testing purposes
+ PostCompositeTask(TimeStamp::Now());
+#ifdef MOZ_WIDGET_ANDROID
+ } else if (mNeedsComposite >= 2 && mIsObservingVsync) {
+ // uh-oh, we already requested a composite at least twice so far, and a
+ // composite hasn't happened yet. It is possible that the vsync observation
+ // is blocked on the main thread, so let's just composite ASAP and not
+ // wait for the vsync. Note that this should only ever happen on Fennec
+ // because there content runs in the same process as the compositor, and so
+ // content can actually block the main thread in this process.
+ PostCompositeTask(TimeStamp::Now());
+#endif
+ } else {
+ SetNeedsComposite();
+ }
+}
+
+void
+CompositorVsyncScheduler::CancelCurrentSetNeedsCompositeTask()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MonitorAutoLock lock(mSetNeedsCompositeMonitor);
+ if (mSetNeedsCompositeTask) {
+ mSetNeedsCompositeTask->Cancel();
+ mSetNeedsCompositeTask = nullptr;
+ }
+ mNeedsComposite = 0;
+}
+
+/**
+ * TODO Potential performance heuristics:
+ * If a composite takes 17 ms, do we composite ASAP or wait until next vsync?
+ * If a layer transaction comes after vsync, do we composite ASAP or wait until
+ * next vsync?
+ * How many skipped vsync events until we stop listening to vsync events?
+ */
+void
+CompositorVsyncScheduler::SetNeedsComposite()
+{
+ if (!CompositorThreadHolder::IsInCompositorThread()) {
+ MonitorAutoLock lock(mSetNeedsCompositeMonitor);
+ RefPtr<CancelableRunnable> task =
+ NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite);
+ mSetNeedsCompositeTask = task;
+ ScheduleTask(task.forget(), 0);
+ return;
+ } else {
+ MonitorAutoLock lock(mSetNeedsCompositeMonitor);
+ mSetNeedsCompositeTask = nullptr;
+ }
+
+ mNeedsComposite++;
+ if (!mIsObservingVsync && mNeedsComposite) {
+ ObserveVsync();
+ }
+}
+
+bool
+CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+ // Called from the vsync dispatch thread. When in the GPU Process, that's
+ // the same as the compositor thread.
+ MOZ_ASSERT_IF(XRE_IsParentProcess(), !CompositorThreadHolder::IsInCompositorThread());
+ MOZ_ASSERT_IF(XRE_GetProcessType() == GeckoProcessType_GPU, CompositorThreadHolder::IsInCompositorThread());
+ MOZ_ASSERT(!NS_IsMainThread());
+ PostCompositeTask(aVsyncTimestamp);
+ return true;
+}
+
+void
+CompositorVsyncScheduler::CancelCurrentCompositeTask()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || NS_IsMainThread());
+ MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
+ if (mCurrentCompositeTask) {
+ mCurrentCompositeTask->Cancel();
+ mCurrentCompositeTask = nullptr;
+ }
+}
+
+void
+CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ {
+ MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
+ mCurrentCompositeTask = nullptr;
+ }
+
+ if ((aVsyncTimestamp < mLastCompose) && !mAsapScheduling) {
+ // We can sometimes get vsync timestamps that are in the past
+ // compared to the last compose with force composites.
+ // In those cases, wait until the next vsync;
+ return;
+ }
+
+ MOZ_ASSERT(mCompositorBridgeParent);
+ if (!mAsapScheduling && mCompositorBridgeParent->IsPendingComposite()) {
+ // If previous composite is still on going, finish it and does a next
+ // composite in a next vsync.
+ mCompositorBridgeParent->FinishPendingComposite();
+ return;
+ }
+
+ DispatchTouchEvents(aVsyncTimestamp);
+ DispatchVREvents(aVsyncTimestamp);
+
+ if (mNeedsComposite || mAsapScheduling) {
+ mNeedsComposite = 0;
+ mLastCompose = aVsyncTimestamp;
+ ComposeToTarget(nullptr);
+ mVsyncNotificationsSkipped = 0;
+
+ TimeDuration compositeFrameTotal = TimeStamp::Now() - aVsyncTimestamp;
+ mozilla::Telemetry::Accumulate(mozilla::Telemetry::COMPOSITE_FRAME_ROUNDTRIP_TIME,
+ compositeFrameTotal.ToMilliseconds());
+ } else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
+ UnobserveVsync();
+ }
+}
+
+void
+CompositorVsyncScheduler::OnForceComposeToTarget()
+{
+ /**
+ * bug 1138502 - There are cases such as during long-running window resizing events
+ * where we receive many sync RecvFlushComposites. We also get vsync notifications which
+ * will increment mVsyncNotificationsSkipped because a composite just occurred. After
+ * enough vsyncs and RecvFlushComposites occurred, we will disable vsync. Then at the next
+ * ScheduleComposite, we will enable vsync, then get a RecvFlushComposite, which will
+ * force us to unobserve vsync again. On some platforms, enabling/disabling vsync is not
+ * free and this oscillating behavior causes a performance hit. In order to avoid this problem,
+ * we reset the mVsyncNotificationsSkipped counter to keep vsync enabled.
+ */
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ mVsyncNotificationsSkipped = 0;
+}
+
+void
+CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ OnForceComposeToTarget();
+ mLastCompose = TimeStamp::Now();
+ ComposeToTarget(aTarget, aRect);
+}
+
+bool
+CompositorVsyncScheduler::NeedsComposite()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ return mNeedsComposite;
+}
+
+void
+CompositorVsyncScheduler::ObserveVsync()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ mWidget->ObserveVsync(mVsyncObserver);
+ mIsObservingVsync = true;
+}
+
+void
+CompositorVsyncScheduler::UnobserveVsync()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ mWidget->ObserveVsync(nullptr);
+ mIsObservingVsync = false;
+}
+
+void
+CompositorVsyncScheduler::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
+{
+}
+
+void
+CompositorVsyncScheduler::DispatchVREvents(TimeStamp aVsyncTimestamp)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ VRManager* vm = VRManager::Get();
+ vm->NotifyVsync(aVsyncTimestamp);
+}
+
+void
+CompositorVsyncScheduler::ScheduleTask(already_AddRefed<CancelableRunnable> aTask,
+ int aTime)
+{
+ MOZ_ASSERT(CompositorThreadHolder::Loop());
+ MOZ_ASSERT(aTime >= 0);
+ CompositorThreadHolder::Loop()->PostDelayedTask(Move(aTask), aTime);
+}
+
+void
+CompositorVsyncScheduler::ResumeComposition()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ mLastCompose = TimeStamp::Now();
+ ComposeToTarget(nullptr);
+}
+
+void
+CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MOZ_ASSERT(mCompositorBridgeParent);
+ mCompositorBridgeParent->CompositeToTarget(aTarget, aRect);
+}
+
+static inline MessageLoop*
+CompositorLoop()
+{
+ return CompositorThreadHolder::Loop();
+}
+
+CompositorBridgeParent::CompositorBridgeParent(CSSToLayoutDeviceScale aScale,
+ const TimeDuration& aVsyncRate,
+ bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize)
+ : mWidget(nullptr)
+ , mScale(aScale)
+ , mVsyncRate(aVsyncRate)
+ , mIsTesting(false)
+ , mPendingTransaction(0)
+ , mPaused(false)
+ , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
+ , mEGLSurfaceSize(aSurfaceSize)
+ , mPauseCompositionMonitor("PauseCompositionMonitor")
+ , mResumeCompositionMonitor("ResumeCompositionMonitor")
+ , mResetCompositorMonitor("ResetCompositorMonitor")
+ , mRootLayerTreeID(0)
+ , mOverrideComposeReadiness(false)
+ , mForceCompositionTask(nullptr)
+ , mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
+ , mCompositorScheduler(nullptr)
+ , mPaintTime(TimeDuration::Forever())
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ , mLastPluginUpdateLayerTreeId(0)
+ , mDeferPluginWindows(false)
+ , mPluginWindowsHidden(false)
+#endif
+{
+ // Always run destructor on the main thread
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
+void
+CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget,
+ const uint64_t& aLayerTreeId,
+ bool aUseAPZ)
+{
+ mWidget = aWidget;
+ mRootLayerTreeID = aLayerTreeId;
+ if (aUseAPZ) {
+ mApzcTreeManager = new APZCTreeManager();
+ }
+
+ // IPDL initialization. mSelfRef is cleared in DeferredDestroy.
+ SetOtherProcessId(base::GetCurrentProcId());
+ mSelfRef = this;
+
+ Initialize();
+}
+
+bool
+CompositorBridgeParent::Bind(Endpoint<PCompositorBridgeParent>&& aEndpoint)
+{
+ if (!aEndpoint.Bind(this)) {
+ return false;
+ }
+ mSelfRef = this;
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvInitialize(const uint64_t& aRootLayerTreeId)
+{
+ mRootLayerTreeID = aRootLayerTreeId;
+
+ Initialize();
+ return true;
+}
+
+void
+CompositorBridgeParent::Initialize()
+{
+ MOZ_ASSERT(CompositorThread(),
+ "The compositor thread must be Initialized before instanciating a CompositorBridgeParent.");
+
+ mCompositorID = 0;
+ // FIXME: This holds on the the fact that right now the only thing that
+ // can destroy this instance is initialized on the compositor thread after
+ // this task has been processed.
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableFunction(&AddCompositor,
+ this, &mCompositorID));
+
+ CompositorLoop()->PostTask(NewRunnableFunction(SetThreadPriority));
+
+
+ { // scope lock
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
+ }
+
+ LayerScope::SetPixelScale(mScale.scale);
+
+ mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
+}
+
+bool
+CompositorBridgeParent::RecvReset(nsTArray<LayersBackend>&& aBackendHints, bool* aResult, TextureFactoryIdentifier* aOutIdentifier)
+{
+ Maybe<TextureFactoryIdentifier> newIdentifier;
+ ResetCompositorTask(aBackendHints, &newIdentifier);
+
+ if (newIdentifier) {
+ *aResult = true;
+ *aOutIdentifier = newIdentifier.value();
+ } else {
+ *aResult = false;
+ }
+
+ return true;
+}
+
+uint64_t
+CompositorBridgeParent::RootLayerTreeId()
+{
+ MOZ_ASSERT(mRootLayerTreeID);
+ return mRootLayerTreeID;
+}
+
+CompositorBridgeParent::~CompositorBridgeParent()
+{
+ InfallibleTArray<PTextureParent*> textures;
+ ManagedPTextureParent(textures);
+ // We expect all textures to be destroyed by now.
+ MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0);
+ for (unsigned int i = 0; i < textures.Length(); ++i) {
+ RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
+ tex->DeallocateDeviceData();
+ }
+}
+
+void
+CompositorBridgeParent::ForceIsFirstPaint()
+{
+ mCompositionManager->ForceIsFirstPaint();
+}
+
+void
+CompositorBridgeParent::StopAndClearResources()
+{
+ if (mForceCompositionTask) {
+ mForceCompositionTask->Cancel();
+ mForceCompositionTask = nullptr;
+ }
+
+ mPaused = true;
+
+ // Ensure that the layer manager is destroyed before CompositorBridgeChild.
+ if (mLayerManager) {
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ ForEachIndirectLayerTree([this] (LayerTreeState* lts, uint64_t) -> void {
+ mLayerManager->ClearCachedResources(lts->mRoot);
+ lts->mLayerManager = nullptr;
+ lts->mParent = nullptr;
+ });
+ mLayerManager->Destroy();
+ mLayerManager = nullptr;
+ mCompositionManager = nullptr;
+ }
+
+ if (mCompositor) {
+ mCompositor->DetachWidget();
+ mCompositor->Destroy();
+ mCompositor = nullptr;
+ }
+
+ // This must be destroyed now since it accesses the widget.
+ if (mCompositorScheduler) {
+ mCompositorScheduler->Destroy();
+ mCompositorScheduler = nullptr;
+ }
+
+ // After this point, it is no longer legal to access the widget.
+ mWidget = nullptr;
+}
+
+bool
+CompositorBridgeParent::RecvWillClose()
+{
+ StopAndClearResources();
+ return true;
+}
+
+void CompositorBridgeParent::DeferredDestroy()
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ MOZ_ASSERT(mCompositorThreadHolder);
+ mCompositorThreadHolder = nullptr;
+ mSelfRef = nullptr;
+}
+
+bool
+CompositorBridgeParent::RecvPause()
+{
+ PauseComposition();
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvResume()
+{
+ ResumeComposition();
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
+ const gfx::IntRect& aRect)
+{
+ RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO);
+ MOZ_ASSERT(target);
+ if (!target) {
+ // We kill the content process rather than have it continue with an invalid
+ // snapshot, that may be too harsh and we could decide to return some sort
+ // of error to the child process and let it deal with it...
+ return false;
+ }
+ ForceComposeToTarget(target, &aRect);
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvFlushRendering()
+{
+ if (mCompositorScheduler->NeedsComposite())
+ {
+ CancelCurrentCompositeTask();
+ ForceComposeToTarget(nullptr);
+ }
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvForcePresent()
+{
+ // During the shutdown sequence mLayerManager may be null
+ if (mLayerManager) {
+ mLayerManager->ForcePresent();
+ }
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion)
+{
+ if (mLayerManager) {
+ mLayerManager->AddInvalidRegion(aRegion);
+ }
+ return true;
+}
+
+void
+CompositorBridgeParent::Invalidate()
+{
+ if (mLayerManager && mLayerManager->GetRoot()) {
+ mLayerManager->AddInvalidRegion(
+ mLayerManager->GetRoot()->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
+ }
+}
+
+bool
+CompositorBridgeParent::RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex)
+{
+ if (mLayerManager) {
+ *aOutStartIndex = mLayerManager->StartFrameTimeRecording(aBufferSize);
+ } else {
+ *aOutStartIndex = 0;
+ }
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvStopFrameTimeRecording(const uint32_t& aStartIndex,
+ InfallibleTArray<float>* intervals)
+{
+ if (mLayerManager) {
+ mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals);
+ }
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+ const uint32_t& aPresShellId)
+{
+ ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId));
+ return true;
+}
+
+void
+CompositorBridgeParent::ClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+ const Maybe<uint32_t>& aPresShellId)
+{
+ if (mLayerManager) {
+ mLayerManager->ClearApproximatelyVisibleRegions(aLayersId, aPresShellId);
+
+ // We need to recomposite to update the minimap.
+ ScheduleComposition();
+ }
+}
+
+bool
+CompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+ const CSSIntRegion& aRegion)
+{
+ if (mLayerManager) {
+ mLayerManager->UpdateApproximatelyVisibleRegion(aGuid, aRegion);
+
+ // We need to recomposite to update the minimap.
+ ScheduleComposition();
+ }
+ return true;
+}
+
+void
+CompositorBridgeParent::ActorDestroy(ActorDestroyReason why)
+{
+ StopAndClearResources();
+
+ RemoveCompositor(mCompositorID);
+
+ mCompositionManager = nullptr;
+
+ if (mApzcTreeManager) {
+ mApzcTreeManager->ClearTree();
+ mApzcTreeManager = nullptr;
+ }
+
+ { // scope lock
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees.erase(mRootLayerTreeID);
+ }
+
+ // There are chances that the ref count reaches zero on the main thread shortly
+ // after this function returns while some ipdl code still needs to run on
+ // this thread.
+ // We must keep the compositor parent alive untill the code handling message
+ // reception is finished on this thread.
+ mSelfRef = this;
+ MessageLoop::current()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::DeferredDestroy));
+}
+
+void
+CompositorBridgeParent::ScheduleRenderOnCompositorThread()
+{
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ScheduleComposition));
+}
+
+void
+CompositorBridgeParent::InvalidateOnCompositorThread()
+{
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::Invalidate));
+}
+
+void
+CompositorBridgeParent::PauseComposition()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
+ "PauseComposition() can only be called on the compositor thread");
+
+ MonitorAutoLock lock(mPauseCompositionMonitor);
+
+ if (!mPaused) {
+ mPaused = true;
+
+ mCompositor->Pause();
+
+ TimeStamp now = TimeStamp::Now();
+ DidComposite(now, now);
+ }
+
+ // if anyone's waiting to make sure that composition really got paused, tell them
+ lock.NotifyAll();
+}
+
+void
+CompositorBridgeParent::ResumeComposition()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
+ "ResumeComposition() can only be called on the compositor thread");
+
+ MonitorAutoLock lock(mResumeCompositionMonitor);
+
+ if (!mCompositor->Resume()) {
+#ifdef MOZ_WIDGET_ANDROID
+ // We can't get a surface. This could be because the activity changed between
+ // the time resume was scheduled and now.
+ __android_log_print(ANDROID_LOG_INFO, "CompositorBridgeParent", "Unable to renew compositor surface; remaining in paused state");
+#endif
+ lock.NotifyAll();
+ return;
+ }
+
+ mPaused = false;
+
+ Invalidate();
+ mCompositorScheduler->ResumeComposition();
+
+ // if anyone's waiting to make sure that composition really got resumed, tell them
+ lock.NotifyAll();
+}
+
+void
+CompositorBridgeParent::ForceComposition()
+{
+ // Cancel the orientation changed state to force composition
+ mForceCompositionTask = nullptr;
+ ScheduleRenderOnCompositorThread();
+}
+
+void
+CompositorBridgeParent::CancelCurrentCompositeTask()
+{
+ mCompositorScheduler->CancelCurrentCompositeTask();
+}
+
+void
+CompositorBridgeParent::SetEGLSurfaceSize(int width, int height)
+{
+ NS_ASSERTION(mUseExternalSurfaceSize, "Compositor created without UseExternalSurfaceSize provided");
+ mEGLSurfaceSize.SizeTo(width, height);
+ if (mCompositor) {
+ mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height));
+ }
+}
+
+void
+CompositorBridgeParent::ResumeCompositionAndResize(int width, int height)
+{
+ SetEGLSurfaceSize(width, height);
+ ResumeComposition();
+}
+
+/*
+ * This will execute a pause synchronously, waiting to make sure that the compositor
+ * really is paused.
+ */
+void
+CompositorBridgeParent::SchedulePauseOnCompositorThread()
+{
+ MonitorAutoLock lock(mPauseCompositionMonitor);
+
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::PauseComposition));
+
+ // Wait until the pause has actually been processed by the compositor thread
+ lock.Wait();
+}
+
+bool
+CompositorBridgeParent::ScheduleResumeOnCompositorThread()
+{
+ MonitorAutoLock lock(mResumeCompositionMonitor);
+
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ResumeComposition));
+
+ // Wait until the resume has actually been processed by the compositor thread
+ lock.Wait();
+
+ return !mPaused;
+}
+
+bool
+CompositorBridgeParent::ScheduleResumeOnCompositorThread(int width, int height)
+{
+ MonitorAutoLock lock(mResumeCompositionMonitor);
+
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod
+ <int, int>(this,
+ &CompositorBridgeParent::ResumeCompositionAndResize,
+ width, height));
+
+ // Wait until the resume has actually been processed by the compositor thread
+ lock.Wait();
+
+ return !mPaused;
+}
+
+void
+CompositorBridgeParent::ScheduleTask(already_AddRefed<CancelableRunnable> task, int time)
+{
+ if (time == 0) {
+ MessageLoop::current()->PostTask(Move(task));
+ } else {
+ MessageLoop::current()->PostDelayedTask(Move(task), time);
+ }
+}
+
+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::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
+ bool aScheduleComposite, uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction, bool aHitTestUpdate)
+{
+ if (!aIsRepeatTransaction &&
+ mLayerManager &&
+ mLayerManager->GetRoot()) {
+ // Process plugin data here to give time for them to update before the next
+ // composition.
+ bool pluginsUpdatedFlag = true;
+ AutoResolveRefLayers resolve(mCompositionManager, this, nullptr,
+ &pluginsUpdatedFlag);
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ // If plugins haven't been updated, stop waiting.
+ if (!pluginsUpdatedFlag) {
+ mWaitForPluginsUntil = TimeStamp();
+ mHaveBlockedForPlugins = false;
+ }
+#endif
+
+ if (mApzcTreeManager && aHitTestUpdate) {
+ mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID,
+ mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber);
+ }
+
+ mLayerManager->NotifyShadowTreeTransaction();
+ }
+ if (aScheduleComposite) {
+ ScheduleComposition();
+ }
+}
+
+void
+CompositorBridgeParent::ScheduleComposition()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ if (mPaused) {
+ return;
+ }
+
+ mCompositorScheduler->ScheduleComposition();
+}
+
+// Go down the composite layer tree, setting properties to match their
+// content-side counterparts.
+/* static */ void
+CompositorBridgeParent::SetShadowProperties(Layer* aLayer)
+{
+ ForEachNode<ForwardIterator>(
+ aLayer,
+ [] (Layer *layer)
+ {
+ if (Layer* maskLayer = layer->GetMaskLayer()) {
+ SetShadowProperties(maskLayer);
+ }
+ for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) {
+ SetShadowProperties(layer->GetAncestorMaskLayerAt(i));
+ }
+
+ // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate.
+ LayerComposite* layerComposite = layer->AsLayerComposite();
+ // Set the layerComposite's base transform to the layer's base transform.
+ layerComposite->SetShadowBaseTransform(layer->GetBaseTransform());
+ layerComposite->SetShadowTransformSetByAnimation(false);
+ layerComposite->SetShadowVisibleRegion(layer->GetVisibleRegion());
+ layerComposite->SetShadowClipRect(layer->GetClipRect());
+ layerComposite->SetShadowOpacity(layer->GetOpacity());
+ layerComposite->SetShadowOpacitySetByAnimation(false);
+ }
+ );
+}
+
+void
+CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect)
+{
+ profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
+ PROFILER_LABEL("CompositorBridgeParent", "Composite",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(),
+ "Composite can only be called on the compositor thread");
+ TimeStamp start = TimeStamp::Now();
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ TimeDuration scheduleDelta = TimeStamp::Now() - mCompositorScheduler->GetExpectedComposeStartTime();
+ if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
+ scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
+ printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
+ scheduleDelta.ToMilliseconds());
+ }
+#endif
+
+ if (!CanComposite()) {
+ TimeStamp end = TimeStamp::Now();
+ DidComposite(start, end);
+ return;
+ }
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ if (!mWaitForPluginsUntil.IsNull() &&
+ mWaitForPluginsUntil > start) {
+ mHaveBlockedForPlugins = true;
+ ScheduleComposition();
+ return;
+ }
+#endif
+
+ /*
+ * AutoResolveRefLayers handles two tasks related to Windows and Linux
+ * plugin window management:
+ * 1) calculating if we have remote content in the view. If we do not have
+ * remote content, all plugin windows for this CompositorBridgeParent (window)
+ * can be hidden since we do not support plugins in chrome when running
+ * under e10s.
+ * 2) Updating plugin position, size, and clip. We do this here while the
+ * remote layer tree is hooked up to to chrome layer tree. This is needed
+ * since plugin clipping can depend on chrome (for example, due to tab modal
+ * prompts). Updates in step 2 are applied via an async ipc message sent
+ * to the main thread.
+ */
+ bool hasRemoteContent = false;
+ bool updatePluginsFlag = true;
+ AutoResolveRefLayers resolve(mCompositionManager, this,
+ &hasRemoteContent,
+ &updatePluginsFlag);
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ // We do not support plugins in local content. When switching tabs
+ // to local pages, hide every plugin associated with the window.
+ if (!hasRemoteContent && gfxVars::BrowserTabsRemoteAutostart() &&
+ mCachedPluginData.Length()) {
+ Unused << SendHideAllPlugins(GetWidget()->GetWidgetKey());
+ mCachedPluginData.Clear();
+ }
+#endif
+
+ if (aTarget) {
+ mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect);
+ } else {
+ mLayerManager->BeginTransaction();
+ }
+
+ SetShadowProperties(mLayerManager->GetRoot());
+
+ if (mForceCompositionTask && !mOverrideComposeReadiness) {
+ if (mCompositionManager->ReadyForCompose()) {
+ mForceCompositionTask->Cancel();
+ mForceCompositionTask = nullptr;
+ } else {
+ return;
+ }
+ }
+
+ mCompositionManager->ComputeRotation();
+
+ TimeStamp time = mIsTesting ? mTestTime : mCompositorScheduler->GetLastComposeTime();
+ bool requestNextFrame = mCompositionManager->TransformShadowTree(time, mVsyncRate);
+ if (requestNextFrame) {
+ ScheduleComposition();
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ // If we have visible windowed plugins then we need to wait for content (and
+ // then the plugins) to have been updated by the active animation.
+ if (!mPluginWindowsHidden && mCachedPluginData.Length()) {
+ mWaitForPluginsUntil = mCompositorScheduler->GetLastComposeTime() + (mVsyncRate * 2);
+ }
+#endif
+ }
+
+ RenderTraceLayers(mLayerManager->GetRoot(), "0000");
+
+#ifdef MOZ_DUMP_PAINTING
+ if (gfxPrefs::DumpHostLayers()) {
+ printf_stderr("Painting --- compositing layer tree:\n");
+ mLayerManager->Dump(/* aSorted = */ true);
+ }
+#endif
+ mLayerManager->SetDebugOverlayWantsNextFrame(false);
+ mLayerManager->EndTransaction(time);
+
+ if (!aTarget) {
+ TimeStamp end = TimeStamp::Now();
+ DidComposite(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".
+ if (!mCompositor->GetCompositeUntilTime().IsNull() ||
+ mLayerManager->DebugOverlayWantsNextFrame()) {
+ ScheduleComposition();
+ }
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ TimeDuration executionTime = TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime();
+ 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 (gfxPrefs::LayersCompositionFrameRate() == 0
+ || mLayerManager->GetCompositor()->GetDiagnosticTypes() & DiagnosticTypes::FLASH_BORDERS) {
+ // Special full-tilt composite mode for performance testing
+ ScheduleComposition();
+ }
+ mCompositor->SetCompositionTime(TimeStamp());
+
+ mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, start);
+ profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
+}
+
+bool
+CompositorBridgeParent::RecvRemotePluginsReady()
+{
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ mWaitForPluginsUntil = TimeStamp();
+ if (mHaveBlockedForPlugins) {
+ mHaveBlockedForPlugins = false;
+ ForceComposeToTarget(nullptr);
+ } else {
+ ScheduleComposition();
+ }
+ return true;
+#else
+ NS_NOTREACHED("CompositorBridgeParent::RecvRemotePluginsReady calls "
+ "unexpected on this platform.");
+ return false;
+#endif
+}
+
+void
+CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect)
+{
+ PROFILER_LABEL("CompositorBridgeParent", "ForceComposeToTarget",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ AutoRestore<bool> override(mOverrideComposeReadiness);
+ mOverrideComposeReadiness = true;
+ mCompositorScheduler->ForceComposeToTarget(aTarget, aRect);
+}
+
+PAPZCTreeManagerParent*
+CompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId)
+{
+ // The main process should pass in 0 because we assume mRootLayerTreeID
+ MOZ_ASSERT(aLayersId == 0);
+
+ // This message doubles as initialization
+ MOZ_ASSERT(!mApzcTreeManager);
+ mApzcTreeManager = new APZCTreeManager();
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
+ MOZ_ASSERT(state.mParent);
+ MOZ_ASSERT(!state.mApzcTreeManagerParent);
+ state.mApzcTreeManagerParent = new APZCTreeManagerParent(mRootLayerTreeID, state.mParent->GetAPZCTreeManager());
+
+ return state.mApzcTreeManagerParent;
+}
+
+bool
+CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
+{
+ delete aActor;
+ return true;
+}
+
+PAPZParent*
+CompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
+{
+ // The main process should pass in 0 because we assume mRootLayerTreeID
+ MOZ_ASSERT(aLayersId == 0);
+
+ RemoteContentController* controller = new RemoteContentController();
+
+ // Increment the controller's refcount before we return it. This will keep the
+ // controller alive until it is released by IPDL in DeallocPAPZParent.
+ controller->AddRef();
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
+ MOZ_ASSERT(!state.mController);
+ state.mController = controller;
+
+ return controller;
+}
+
+bool
+CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
+{
+ RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
+ controller->Release();
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
+{
+ // The main process should pass in 0 because we assume mRootLayerTreeID
+ MOZ_ASSERT(aLayersId == 0);
+ *aHasAPZ = AsyncPanZoomEnabled();
+ return true;
+}
+
+RefPtr<APZCTreeManager>
+CompositorBridgeParent::GetAPZCTreeManager()
+{
+ return mApzcTreeManager;
+}
+
+bool
+CompositorBridgeParent::CanComposite()
+{
+ return mLayerManager &&
+ mLayerManager->GetRoot() &&
+ !mPaused;
+}
+
+void
+CompositorBridgeParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig,
+ bool aIsFirstPaint)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ if (!aIsFirstPaint &&
+ !mCompositionManager->IsFirstPaint() &&
+ mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) {
+ if (mForceCompositionTask != nullptr) {
+ mForceCompositionTask->Cancel();
+ }
+ RefPtr<CancelableRunnable> task =
+ NewCancelableRunnableMethod(this, &CompositorBridgeParent::ForceComposition);
+ mForceCompositionTask = task;
+ ScheduleTask(task.forget(), gfxPrefs::OrientationSyncMillis());
+ }
+}
+
+void
+CompositorBridgeParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const uint64_t& aTransactionId,
+ const TargetConfig& aTargetConfig,
+ const InfallibleTArray<PluginWindowData>& aUnused,
+ bool aIsFirstPaint,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ int32_t aPaintSyncId,
+ bool aHitTestUpdate)
+{
+ ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint);
+
+ // 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(aTargetConfig.naturalBounds());
+ mLayerManager->SetRegionToClear(aTargetConfig.clearRegion());
+ mLayerManager->GetCompositor()->SetScreenRotation(aTargetConfig.rotation());
+
+ mCompositionManager->Updated(aIsFirstPaint, aTargetConfig, aPaintSyncId);
+ Layer* root = aLayerTree->GetRoot();
+ mLayerManager->SetRoot(root);
+
+ if (mApzcTreeManager && !aIsRepeatTransaction && aHitTestUpdate) {
+ AutoResolveRefLayers resolve(mCompositionManager);
+
+ mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID, root, aIsFirstPaint,
+ mRootLayerTreeID, aPaintSequenceNumber);
+ }
+
+ // 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(aTransactionId == 1 || aTransactionId > mPendingTransaction);
+ mPendingTransaction = aTransactionId;
+
+ if (root) {
+ SetShadowProperties(root);
+ }
+ if (aScheduleComposite) {
+ ScheduleComposition();
+ if (mPaused) {
+ TimeStamp now = TimeStamp::Now();
+ DidComposite(now, now);
+ }
+ }
+ mLayerManager->NotifyShadowTreeTransaction();
+}
+
+void
+CompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree)
+{
+ ScheduleComposition();
+}
+
+bool
+CompositorBridgeParent::SetTestSampleTime(LayerTransactionParent* aLayerTree,
+ const TimeStamp& aTime)
+{
+ if (aTime.IsNull()) {
+ return false;
+ }
+
+ mIsTesting = true;
+ mTestTime = aTime;
+
+ bool testComposite = mCompositionManager &&
+ mCompositorScheduler->NeedsComposite();
+
+ // Update but only if we were already scheduled to animate
+ if (testComposite) {
+ AutoResolveRefLayers resolve(mCompositionManager);
+ bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime, mVsyncRate);
+ if (!requestNextFrame) {
+ CancelCurrentCompositeTask();
+ // Pretend we composited in case someone is wating for this event.
+ TimeStamp now = TimeStamp::Now();
+ DidComposite(now, now);
+ }
+ }
+
+ return true;
+}
+
+void
+CompositorBridgeParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
+{
+ mIsTesting = false;
+}
+
+void
+CompositorBridgeParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
+{
+ // NOTE: This should only be used for testing. For example, when mIsTesting is
+ // true or when called from test-only methods like
+ // LayerTransactionParent::RecvGetAnimationTransform.
+
+ // Synchronously update the layer tree
+ if (aLayerTree->GetRoot()) {
+ AutoResolveRefLayers resolve(mCompositionManager);
+ SetShadowProperties(mLayerManager->GetRoot());
+
+ TimeStamp time = mIsTesting ? mTestTime : mCompositorScheduler->GetLastComposeTime();
+ bool requestNextFrame =
+ mCompositionManager->TransformShadowTree(time, mVsyncRate,
+ AsyncCompositionManager::TransformsToSkip::APZ);
+ if (!requestNextFrame) {
+ CancelCurrentCompositeTask();
+ // Pretend we composited in case someone is waiting for this event.
+ TimeStamp now = TimeStamp::Now();
+ DidComposite(now, now);
+ }
+ }
+}
+
+bool
+CompositorBridgeParent::RecvGetFrameUniformity(FrameUniformityData* aOutData)
+{
+ mCompositionManager->GetFrameUniformity(aOutData);
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvRequestOverfill()
+{
+ uint32_t overfillRatio = mCompositor->GetFillRatio();
+ Unused << SendOverfill(overfillRatio);
+ return true;
+}
+
+void
+CompositorBridgeParent::FlushApzRepaints(const LayerTransactionParent* aLayerTree)
+{
+ MOZ_ASSERT(mApzcTreeManager);
+ uint64_t layersId = aLayerTree->GetId();
+ if (layersId == 0) {
+ // The request is coming from the parent-process layer tree, so we should
+ // use the compositor's root layer tree id.
+ layersId = mRootLayerTreeID;
+ }
+ RefPtr<CompositorBridgeParent> self = this;
+ APZThreadUtils::RunOnControllerThread(NS_NewRunnableFunction([=] () {
+ self->mApzcTreeManager->FlushApzRepaints(layersId);
+ }));
+}
+
+void
+CompositorBridgeParent::GetAPZTestData(const LayerTransactionParent* aLayerTree,
+ APZTestData* aOutData)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ *aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;
+}
+
+void
+CompositorBridgeParent::SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
+ const uint64_t& aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets)
+{
+ if (!mApzcTreeManager) {
+ return;
+ }
+ // Need to specifically bind this since it's overloaded.
+ void (APZCTreeManager::*setTargetApzcFunc)
+ (uint64_t, const nsTArray<ScrollableLayerGuid>&) =
+ &APZCTreeManager::SetTargetAPZC;
+ RefPtr<Runnable> task = NewRunnableMethod
+ <uint64_t, StoreCopyPassByConstLRef<nsTArray<ScrollableLayerGuid>>>
+ (mApzcTreeManager.get(), setTargetApzcFunc, aInputBlockId, aTargets);
+ APZThreadUtils::RunOnControllerThread(task.forget());
+
+}
+
+void
+CompositorBridgeParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
+{
+ NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
+ NS_ASSERTION(!mCompositor, "Already initialised mCompositor");
+
+ mCompositor = NewCompositor(aBackendHints);
+ if (!mCompositor) {
+ return;
+ }
+
+ mLayerManager = new LayerManagerComposite(mCompositor);
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = mLayerManager;
+}
+
+RefPtr<Compositor>
+CompositorBridgeParent::NewCompositor(const nsTArray<LayersBackend>& aBackendHints)
+{
+ for (size_t i = 0; i < aBackendHints.Length(); ++i) {
+ RefPtr<Compositor> compositor;
+ if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
+ compositor = new CompositorOGL(this,
+ mWidget,
+ mEGLSurfaceSize.width,
+ mEGLSurfaceSize.height,
+ mUseExternalSurfaceSize);
+ } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) {
+#ifdef MOZ_WIDGET_GTK
+ if (gfxVars::UseXRender()) {
+ compositor = new X11BasicCompositor(this, mWidget);
+ } else
+#endif
+ {
+ compositor = new BasicCompositor(this, mWidget);
+ }
+#ifdef XP_WIN
+ } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) {
+ compositor = new CompositorD3D11(this, mWidget);
+ } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9) {
+ compositor = new CompositorD3D9(this, mWidget);
+#endif
+ }
+ nsCString failureReason;
+ if (compositor && compositor->Initialize(&failureReason)) {
+ if (failureReason.IsEmpty()){
+ failureReason = "SUCCESS";
+ }
+
+ // should only report success here
+ if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL){
+ Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID, failureReason);
+ }
+#ifdef XP_WIN
+ else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9){
+ Telemetry::Accumulate(Telemetry::D3D9_COMPOSITING_FAILURE_ID, failureReason);
+ }
+ else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11){
+ Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID, failureReason);
+ }
+#endif
+
+ compositor->SetCompositorID(mCompositorID);
+ return compositor;
+ }
+
+ // report any failure reasons here
+ if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL){
+ gfxCriticalNote << "[OPENGL] Failed to init compositor with reason: "
+ << failureReason.get();
+ Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID, failureReason);
+ }
+#ifdef XP_WIN
+ else if (aBackendHints[i] == LayersBackend::LAYERS_D3D9){
+ gfxCriticalNote << "[D3D9] Failed to init compositor with reason: "
+ << failureReason.get();
+ Telemetry::Accumulate(Telemetry::D3D9_COMPOSITING_FAILURE_ID, failureReason);
+ }
+ else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11){
+ gfxCriticalNote << "[D3D11] Failed to init compositor with reason: "
+ << failureReason.get();
+ Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID, failureReason);
+ }
+#endif
+ }
+
+ return nullptr;
+}
+
+PLayerTransactionParent*
+CompositorBridgeParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
+ const uint64_t& aId,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ bool *aSuccess)
+{
+ MOZ_ASSERT(aId == 0);
+
+ InitializeLayerManager(aBackendHints);
+
+ if (!mLayerManager) {
+ NS_WARNING("Failed to initialise Compositor");
+ *aSuccess = false;
+ LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, 0);
+ p->AddIPDLReference();
+ return p;
+ }
+
+ mCompositionManager = new AsyncCompositionManager(mLayerManager);
+ *aSuccess = true;
+
+ *aTextureFactoryIdentifier = mCompositor->GetTextureFactoryIdentifier();
+ LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, 0);
+ p->AddIPDLReference();
+ return p;
+}
+
+bool
+CompositorBridgeParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor)
+{
+ static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference();
+ return true;
+}
+
+CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(uint64_t id)
+{
+ CompositorMap::iterator it = sCompositorMap->find(id);
+ return it != sCompositorMap->end() ? it->second : nullptr;
+}
+
+void CompositorBridgeParent::AddCompositor(CompositorBridgeParent* compositor, uint64_t* outID)
+{
+ static uint64_t sNextID = 1;
+
+ ++sNextID;
+ (*sCompositorMap)[sNextID] = compositor;
+ *outID = sNextID;
+}
+
+CompositorBridgeParent* CompositorBridgeParent::RemoveCompositor(uint64_t id)
+{
+ CompositorMap::iterator it = sCompositorMap->find(id);
+ if (it == sCompositorMap->end()) {
+ return nullptr;
+ }
+ CompositorBridgeParent *retval = it->second;
+ sCompositorMap->erase(it);
+ return retval;
+}
+
+void
+CompositorBridgeParent::NotifyVsync(const TimeStamp& aTimeStamp, const uint64_t& aLayersId)
+{
+ MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ auto it = sIndirectLayerTrees.find(aLayersId);
+ if (it == sIndirectLayerTrees.end())
+ return;
+
+ CompositorBridgeParent* cbp = it->second.mParent;
+ if (!cbp || !cbp->mWidget)
+ return;
+
+ RefPtr<VsyncObserver> obs = cbp->mWidget->GetVsyncObserver();
+ if (!obs)
+ return;
+
+ obs->NotifyVsync(aTimeStamp);
+}
+
+bool
+CompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ NotifyChildCreated(child);
+ return true;
+}
+
+bool
+CompositorBridgeParent::RecvNotifyChildRecreated(const uint64_t& aChild)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+
+ if (sIndirectLayerTrees.find(aChild) != sIndirectLayerTrees.end()) {
+ // Invalid to register the same layer tree twice.
+ return false;
+ }
+
+ NotifyChildCreated(aChild);
+ return true;
+}
+
+void
+CompositorBridgeParent::NotifyChildCreated(uint64_t aChild)
+{
+ sIndirectLayerTreesLock->AssertCurrentThreadOwns();
+ sIndirectLayerTrees[aChild].mParent = this;
+ sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
+}
+
+bool
+CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
+{
+ APZCTreeManagerParent* parent;
+ {
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ NotifyChildCreated(child);
+ if (sIndirectLayerTrees[child].mLayerTree) {
+ sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager);
+ }
+ parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
+ }
+
+ if (mApzcTreeManager && parent) {
+ parent->ChildAdopted(mApzcTreeManager);
+ }
+ return true;
+}
+
+static void
+EraseLayerState(uint64_t aId)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+
+ auto iter = sIndirectLayerTrees.find(aId);
+ if (iter != sIndirectLayerTrees.end()) {
+ CompositorBridgeParent* parent = iter->second.mParent;
+ if (parent) {
+ parent->ClearApproximatelyVisibleRegions(aId, Nothing());
+ }
+
+ sIndirectLayerTrees.erase(iter);
+ }
+}
+
+/*static*/ void
+CompositorBridgeParent::DeallocateLayerTreeId(uint64_t aId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ // Here main thread notifies compositor to remove an element from
+ // sIndirectLayerTrees. This removed element might be queried soon.
+ // Checking the elements of sIndirectLayerTrees exist or not before using.
+ if (!CompositorLoop()) {
+ gfxCriticalError() << "Attempting to post to a invalid Compositor Loop";
+ return;
+ }
+ CompositorLoop()->PostTask(NewRunnableFunction(&EraseLayerState, aId));
+}
+
+static void
+UpdateControllerForLayersId(uint64_t aLayersId,
+ GeckoContentController* aController)
+{
+ // Adopt ref given to us by SetControllerForLayerTree()
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees[aLayersId].mController =
+ already_AddRefed<GeckoContentController>(aController);
+}
+
+ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(APZCTreeManager* aApzctm,
+ uint64_t aLayersId,
+ Layer* aRoot,
+ GeckoContentController* aController)
+ : mLayersId(aLayersId)
+{
+ EnsureLayerTreeMapReady();
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees[aLayersId].mRoot = aRoot;
+ sIndirectLayerTrees[aLayersId].mController = aController;
+}
+
+ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration()
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees.erase(mLayersId);
+}
+
+/*static*/ void
+CompositorBridgeParent::SetControllerForLayerTree(uint64_t aLayersId,
+ GeckoContentController* aController)
+{
+ // This ref is adopted by UpdateControllerForLayersId().
+ aController->AddRef();
+ CompositorLoop()->PostTask(NewRunnableFunction(&UpdateControllerForLayersId,
+ aLayersId,
+ aController));
+}
+
+/*static*/ already_AddRefed<APZCTreeManager>
+CompositorBridgeParent::GetAPZCTreeManager(uint64_t aLayersId)
+{
+ EnsureLayerTreeMapReady();
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aLayersId);
+ if (sIndirectLayerTrees.end() == cit) {
+ return nullptr;
+ }
+ LayerTreeState* lts = &cit->second;
+
+ RefPtr<APZCTreeManager> apzctm = lts->mParent
+ ? lts->mParent->mApzcTreeManager.get()
+ : nullptr;
+ return apzctm.forget();
+}
+
+static void
+InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
+{
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ VsyncPayload* payload = new VsyncPayload(aVsyncTimestamp);
+ PROFILER_MARKER_PAYLOAD("VsyncTimestamp", payload);
+#endif
+}
+
+/*static */ void
+CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
+{
+ // Called in the vsync thread
+ if (profiler_is_active() && CompositorThreadHolder::IsActive()) {
+ CompositorLoop()->PostTask(
+ NewRunnableFunction(InsertVsyncProfilerMarker, aVsyncTimestamp));
+ }
+}
+
+widget::PCompositorWidgetParent*
+CompositorBridgeParent::AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData)
+{
+#if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
+ if (mWidget) {
+ // Should not create two widgets on the same compositor.
+ return nullptr;
+ }
+
+ widget::CompositorWidgetParent* widget =
+ new widget::CompositorWidgetParent(aInitData);
+ widget->AddRef();
+
+ // Sending the constructor acts as initialization as well.
+ mWidget = widget;
+ return widget;
+#else
+ return nullptr;
+#endif
+}
+
+bool
+CompositorBridgeParent::DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor)
+{
+#if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING)
+ static_cast<widget::CompositorWidgetParent*>(aActor)->Release();
+ return true;
+#else
+ return false;
+#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;
+}
+
+MetricsSharingController*
+CompositorBridgeParent::LayerTreeState::CrossProcessSharingController() const
+{
+ return mCrossProcessParent;
+}
+
+MetricsSharingController*
+CompositorBridgeParent::LayerTreeState::InProcessSharingController() const
+{
+ return mParent;
+}
+
+void
+CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart,
+ TimeStamp& aCompositeEnd)
+{
+ Unused << SendDidComposite(0, mPendingTransaction, aCompositeStart, aCompositeEnd);
+ mPendingTransaction = 0;
+
+ if (mLayerManager) {
+ nsTArray<ImageCompositeNotification> notifications;
+ mLayerManager->ExtractImageCompositeNotifications(&notifications);
+ if (!notifications.IsEmpty()) {
+ Unused << ImageBridgeParent::NotifyImageComposites(notifications);
+ }
+ }
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
+ if (lts->mCrossProcessParent && lts->mParent == this) {
+ CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
+ cpcp->DidComposite(aLayersId, aCompositeStart, aCompositeEnd);
+ }
+ });
+}
+
+void
+CompositorBridgeParent::InvalidateRemoteLayers()
+{
+ MOZ_ASSERT(CompositorLoop() == MessageLoop::current());
+
+ Unused << PCompositorBridgeParent::SendInvalidateLayers(0);
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ ForEachIndirectLayerTree([] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
+ if (lts->mCrossProcessParent) {
+ CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
+ Unused << cpcp->SendInvalidateLayers(aLayersId);
+ }
+ });
+}
+
+bool
+CompositorBridgeParent::ResetCompositor(const nsTArray<LayersBackend>& aBackendHints,
+ TextureFactoryIdentifier* aOutIdentifier)
+{
+ Maybe<TextureFactoryIdentifier> newIdentifier;
+ {
+ MonitorAutoLock lock(mResetCompositorMonitor);
+
+ CompositorLoop()->PostTask(NewRunnableMethod
+ <StoreCopyPassByConstLRef<nsTArray<LayersBackend>>,
+ Maybe<TextureFactoryIdentifier>*>(this,
+ &CompositorBridgeParent::ResetCompositorTask,
+ aBackendHints,
+ &newIdentifier));
+
+ mResetCompositorMonitor.Wait();
+ }
+
+ if (!newIdentifier) {
+ return false;
+ }
+
+ *aOutIdentifier = newIdentifier.value();
+ return true;
+}
+
+// Invoked on the compositor thread. The main thread is waiting on the given
+// monitor.
+void
+CompositorBridgeParent::ResetCompositorTask(const nsTArray<LayersBackend>& aBackendHints,
+ Maybe<TextureFactoryIdentifier>* aOutNewIdentifier)
+{
+ // Perform the reset inside a lock, so the main thread can wake up as soon as
+ // possible. We notify child processes (if necessary) outside the lock.
+ Maybe<TextureFactoryIdentifier> newIdentifier;
+ {
+ MonitorAutoLock lock(mResetCompositorMonitor);
+
+ newIdentifier = ResetCompositorImpl(aBackendHints);
+ *aOutNewIdentifier = newIdentifier;
+
+ mResetCompositorMonitor.NotifyAll();
+ }
+
+ // NOTE: |aBackendHints|, and |aOutNewIdentifier| are now all invalid since
+ // they are allocated on ResetCompositor's stack on the main thread, which
+ // is no longer waiting on the lock.
+
+ if (!newIdentifier) {
+ // No compositor change; nothing to do.
+ return;
+ }
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ ForEachIndirectLayerTree([&] (LayerTreeState* lts, uint64_t layersId) -> void {
+ if (CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent) {
+ Unused << cpcp->SendCompositorUpdated(layersId, newIdentifier.value());
+
+ if (LayerTransactionParent* ltp = lts->mLayerTree) {
+ ltp->AddPendingCompositorUpdate();
+ }
+ lts->mPendingCompositorUpdates++;
+ }
+ });
+}
+
+Maybe<TextureFactoryIdentifier>
+CompositorBridgeParent::ResetCompositorImpl(const nsTArray<LayersBackend>& aBackendHints)
+{
+ if (!mLayerManager) {
+ return Nothing();
+ }
+
+ RefPtr<Compositor> compositor = NewCompositor(aBackendHints);
+ if (!compositor) {
+ MOZ_RELEASE_ASSERT(compositor, "Failed to reset compositor.");
+ }
+
+ // Don't bother changing from basic->basic.
+ if (mCompositor &&
+ mCompositor->GetBackendType() == LayersBackend::LAYERS_BASIC &&
+ compositor->GetBackendType() == LayersBackend::LAYERS_BASIC)
+ {
+ return Nothing();
+ }
+
+ if (mCompositor) {
+ mCompositor->SetInvalid();
+ }
+ mCompositor = compositor;
+ mLayerManager->ChangeCompositor(compositor);
+
+ return Some(compositor->GetTextureFactoryIdentifier());
+}
+
+static void
+OpenCompositor(RefPtr<CrossProcessCompositorBridgeParent> aCompositor,
+ Endpoint<PCompositorBridgeParent>&& aEndpoint)
+{
+ aCompositor->Bind(Move(aEndpoint));
+}
+
+/* static */ bool
+CompositorBridgeParent::CreateForContent(Endpoint<PCompositorBridgeParent>&& aEndpoint)
+{
+ gfxPlatform::InitLayersIPC();
+
+ RefPtr<CrossProcessCompositorBridgeParent> cpcp =
+ new CrossProcessCompositorBridgeParent();
+
+ CompositorLoop()->PostTask(NewRunnableFunction(OpenCompositor, cpcp, Move(aEndpoint)));
+ return true;
+}
+
+static void
+UpdateIndirectTree(uint64_t aId, Layer* aRoot, const TargetConfig& aTargetConfig)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ sIndirectLayerTrees[aId].mRoot = aRoot;
+ sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig;
+}
+
+/* static */ CompositorBridgeParent::LayerTreeState*
+CompositorBridgeParent::GetIndirectShadowTree(uint64_t aId)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId);
+ if (sIndirectLayerTrees.end() == cit) {
+ return nullptr;
+ }
+ return &cit->second;
+}
+
+static CompositorBridgeParent::LayerTreeState*
+GetStateForRoot(uint64_t aContentLayersId, const MonitorAutoLock& aProofOfLock)
+{
+ CompositorBridgeParent::LayerTreeState* state = nullptr;
+ LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aContentLayersId);
+ if (sIndirectLayerTrees.end() != itr) {
+ state = &itr->second;
+ }
+
+ // |state| is the state for the content process, but we want the APZCTMParent
+ // for the parent process owning that content process. So we have to jump to
+ // the LayerTreeState for the root layer tree id for that layer tree, and use
+ // the mApzcTreeManagerParent from that. This should also work with nested
+ // content processes, because RootLayerTreeId() will bypass any intermediate
+ // processes' ids and go straight to the root.
+ if (state) {
+ uint64_t rootLayersId = state->mParent->RootLayerTreeId();
+ itr = sIndirectLayerTrees.find(rootLayersId);
+ state = (sIndirectLayerTrees.end() != itr) ? &itr->second : nullptr;
+ }
+
+ return state;
+}
+
+/* static */ APZCTreeManagerParent*
+CompositorBridgeParent::GetApzcTreeManagerParentForRoot(uint64_t aContentLayersId)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState* state =
+ GetStateForRoot(aContentLayersId, lock);
+ return state ? state->mApzcTreeManagerParent : nullptr;
+}
+
+/* static */ GeckoContentController*
+CompositorBridgeParent::GetGeckoContentControllerForRoot(uint64_t aContentLayersId)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState* state =
+ GetStateForRoot(aContentLayersId, lock);
+ return state ? state->mController.get() : nullptr;
+}
+
+PTextureParent*
+CompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aId,
+ const uint64_t& aSerial)
+{
+ return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+bool
+CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
+{
+ return TextureHost::DestroyIPDLActor(actor);
+}
+
+bool
+CompositorBridgeParent::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+//#define PLUGINS_LOG(...) printf_stderr("CP [%s]: ", __FUNCTION__);
+// printf_stderr(__VA_ARGS__);
+// printf_stderr("\n");
+#define PLUGINS_LOG(...)
+
+bool
+CompositorBridgeParent::UpdatePluginWindowState(uint64_t aId)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& lts = sIndirectLayerTrees[aId];
+ if (!lts.mParent) {
+ PLUGINS_LOG("[%" PRIu64 "] layer tree compositor parent pointer is null", aId);
+ return false;
+ }
+
+ // Check if this layer tree has received any shadow layer updates
+ if (!lts.mUpdatedPluginDataAvailable) {
+ PLUGINS_LOG("[%" PRIu64 "] no plugin data", aId);
+ return false;
+ }
+
+ // pluginMetricsChanged tracks whether we need to send plugin update
+ // data to the main thread. If we do we'll have to block composition,
+ // which we want to avoid if at all possible.
+ bool pluginMetricsChanged = false;
+
+ // Same layer tree checks
+ if (mLastPluginUpdateLayerTreeId == aId) {
+ // no plugin data and nothing has changed, bail.
+ if (!mCachedPluginData.Length() && !lts.mPluginData.Length()) {
+ PLUGINS_LOG("[%" PRIu64 "] no data, no changes", aId);
+ return false;
+ }
+
+ if (mCachedPluginData.Length() == lts.mPluginData.Length()) {
+ // check for plugin data changes
+ for (uint32_t idx = 0; idx < lts.mPluginData.Length(); idx++) {
+ if (!(mCachedPluginData[idx] == lts.mPluginData[idx])) {
+ pluginMetricsChanged = true;
+ break;
+ }
+ }
+ } else {
+ // array lengths don't match, need to update
+ pluginMetricsChanged = true;
+ }
+ } else {
+ // exchanging layer trees, we need to update
+ pluginMetricsChanged = true;
+ }
+
+ // Check if plugin windows are currently hidden due to scrolling
+ if (mDeferPluginWindows) {
+ PLUGINS_LOG("[%" PRIu64 "] suppressing", aId);
+ return false;
+ }
+
+ // If the plugin windows were hidden but now are not, we need to force
+ // update the metrics to make sure they are visible again.
+ if (mPluginWindowsHidden) {
+ PLUGINS_LOG("[%" PRIu64 "] re-showing", aId);
+ mPluginWindowsHidden = false;
+ pluginMetricsChanged = true;
+ }
+
+ if (!lts.mPluginData.Length()) {
+ // Don't hide plugins if the previous remote layer tree didn't contain any.
+ if (!mCachedPluginData.Length()) {
+ PLUGINS_LOG("[%" PRIu64 "] nothing to hide", aId);
+ return false;
+ }
+
+ uintptr_t parentWidget = GetWidget()->GetWidgetKey();
+
+ // We will pass through here in cases where the previous shadow layer
+ // tree contained visible plugins and the new tree does not. All we need
+ // to do here is hide the plugins for the old tree, so don't waste time
+ // calculating clipping.
+ mPluginsLayerOffset = nsIntPoint(0,0);
+ mPluginsLayerVisibleRegion.SetEmpty();
+ Unused << lts.mParent->SendHideAllPlugins(parentWidget);
+ lts.mUpdatedPluginDataAvailable = false;
+ PLUGINS_LOG("[%" PRIu64 "] hide all", aId);
+ } else {
+ // Retrieve the offset and visible region of the layer that hosts
+ // the plugins, CompositorBridgeChild needs these in calculating proper
+ // plugin clipping.
+ LayerTransactionParent* layerTree = lts.mLayerTree;
+ Layer* contentRoot = layerTree->GetRoot();
+ if (contentRoot) {
+ nsIntPoint offset;
+ nsIntRegion visibleRegion;
+ if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion,
+ &offset)) {
+ // Check to see if these values have changed, if so we need to
+ // update plugin window position within the window.
+ if (!pluginMetricsChanged &&
+ mPluginsLayerVisibleRegion == visibleRegion &&
+ mPluginsLayerOffset == offset) {
+ PLUGINS_LOG("[%" PRIu64 "] no change", aId);
+ return false;
+ }
+ mPluginsLayerOffset = offset;
+ mPluginsLayerVisibleRegion = visibleRegion;
+ Unused << lts.mParent->SendUpdatePluginConfigurations(
+ LayoutDeviceIntPoint::FromUnknownPoint(offset),
+ LayoutDeviceIntRegion::FromUnknownRegion(visibleRegion),
+ lts.mPluginData);
+ lts.mUpdatedPluginDataAvailable = false;
+ PLUGINS_LOG("[%" PRIu64 "] updated", aId);
+ } else {
+ PLUGINS_LOG("[%" PRIu64 "] no visibility data", aId);
+ return false;
+ }
+ } else {
+ PLUGINS_LOG("[%" PRIu64 "] no content root", aId);
+ return false;
+ }
+ }
+
+ mLastPluginUpdateLayerTreeId = aId;
+ mCachedPluginData = lts.mPluginData;
+ return true;
+}
+
+void
+CompositorBridgeParent::ScheduleShowAllPluginWindows()
+{
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ShowAllPluginWindows));
+}
+
+void
+CompositorBridgeParent::ShowAllPluginWindows()
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ mDeferPluginWindows = false;
+ ScheduleComposition();
+}
+
+void
+CompositorBridgeParent::ScheduleHideAllPluginWindows()
+{
+ MOZ_ASSERT(CompositorLoop());
+ CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::HideAllPluginWindows));
+}
+
+void
+CompositorBridgeParent::HideAllPluginWindows()
+{
+ MOZ_ASSERT(!NS_IsMainThread());
+ // No plugins in the cache implies no plugins to manage
+ // in this content.
+ if (!mCachedPluginData.Length() || mDeferPluginWindows) {
+ return;
+ }
+
+ uintptr_t parentWidget = GetWidget()->GetWidgetKey();
+
+ mDeferPluginWindows = true;
+ mPluginWindowsHidden = true;
+
+#if defined(XP_WIN)
+ // We will get an async reply that this has happened and then send hide.
+ mWaitForPluginsUntil = TimeStamp::Now() + mVsyncRate;
+ Unused << SendCaptureAllPlugins(parentWidget);
+#else
+ Unused << SendHideAllPlugins(parentWidget);
+ ScheduleComposition();
+#endif
+}
+#endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+
+bool
+CompositorBridgeParent::RecvAllPluginsCaptured()
+{
+#if defined(XP_WIN)
+ mWaitForPluginsUntil = TimeStamp();
+ mHaveBlockedForPlugins = false;
+ ForceComposeToTarget(nullptr);
+ Unused << SendHideAllPlugins(GetWidget()->GetWidgetKey());
+ return true;
+#else
+ MOZ_ASSERT_UNREACHABLE(
+ "CompositorBridgeParent::RecvAllPluginsCaptured calls unexpected.");
+ return false;
+#endif
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h
new file mode 100644
index 000000000..58052003f
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -0,0 +1,688 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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_CompositorBridgeParent_h
+#define mozilla_layers_CompositorBridgeParent_h
+
+// Enable this pref to turn on compositor performance warning.
+// This will print warnings if the compositor isn't meeting
+// its responsiveness objectives:
+// 1) Compose a frame within 15ms of receiving a ScheduleCompositeCall
+// 2) Unless a frame was composited within the throttle threshold in
+// which the deadline will be 15ms + throttle threshold
+//#define COMPOSITOR_PERFORMANCE_WARNING
+
+#include <stdint.h> // for uint64_t
+#include "Layers.h" // for Layer
+#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/Maybe.h"
+#include "mozilla/Monitor.h" // for Monitor
+#include "mozilla/RefPtr.h" // for RefPtr
+#include "mozilla/TimeStamp.h" // for TimeStamp
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/SharedMemory.h"
+#include "mozilla/layers/CompositorController.h"
+#include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
+#include "mozilla/layers/LayersMessages.h" // for TargetConfig
+#include "mozilla/layers/MetricsSharingController.h"
+#include "mozilla/layers/PCompositorBridgeParent.h"
+#include "mozilla/layers/APZTestData.h"
+#include "mozilla/widget/CompositorWidget.h"
+#include "nsISupportsImpl.h"
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "mozilla/VsyncDispatcher.h"
+
+class MessageLoop;
+class nsIWidget;
+
+namespace mozilla {
+
+class CancelableRunnable;
+
+namespace gfx {
+class DrawTarget;
+class GPUProcessManager;
+class GPUParent;
+} // namespace gfx
+
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+class APZCTreeManager;
+class APZCTreeManagerParent;
+class AsyncCompositionManager;
+class Compositor;
+class CompositorBridgeParent;
+class LayerManagerComposite;
+class LayerTransactionParent;
+class PAPZParent;
+class CrossProcessCompositorBridgeParent;
+class CompositorThreadHolder;
+class InProcessCompositorSession;
+
+struct ScopedLayerTreeRegistration
+{
+ ScopedLayerTreeRegistration(APZCTreeManager* aApzctm,
+ uint64_t aLayersId,
+ Layer* aRoot,
+ GeckoContentController* aController);
+ ~ScopedLayerTreeRegistration();
+
+private:
+ uint64_t mLayersId;
+};
+
+/**
+ * Manages the vsync (de)registration and tracking on behalf of the
+ * compositor when it need to paint.
+ * Turns vsync notifications into scheduled composites.
+ **/
+class CompositorVsyncScheduler
+{
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler)
+
+public:
+ explicit CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent,
+ widget::CompositorWidget* aWidget);
+
+ bool NotifyVsync(TimeStamp aVsyncTimestamp);
+ void SetNeedsComposite();
+ void OnForceComposeToTarget();
+
+ void ScheduleTask(already_AddRefed<CancelableRunnable>, int);
+ void ResumeComposition();
+ void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
+ void PostCompositeTask(TimeStamp aCompositeTimestamp);
+ void Destroy();
+ void ScheduleComposition();
+ void CancelCurrentCompositeTask();
+ bool NeedsComposite();
+ void Composite(TimeStamp aVsyncTimestamp);
+ void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect);
+
+ const TimeStamp& GetLastComposeTime()
+ {
+ return mLastCompose;
+ }
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ const TimeStamp& GetExpectedComposeStartTime()
+ {
+ return mExpectedComposeStartTime;
+ }
+#endif
+
+private:
+ virtual ~CompositorVsyncScheduler();
+
+ void NotifyCompositeTaskExecuted();
+ void ObserveVsync();
+ void UnobserveVsync();
+ void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
+ void DispatchVREvents(TimeStamp aVsyncTimestamp);
+ void CancelCurrentSetNeedsCompositeTask();
+
+ class Observer final : public VsyncObserver
+ {
+ public:
+ explicit Observer(CompositorVsyncScheduler* aOwner);
+ virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
+ void Destroy();
+ private:
+ virtual ~Observer();
+
+ Mutex mMutex;
+ // Hold raw pointer to avoid mutual reference.
+ CompositorVsyncScheduler* mOwner;
+ };
+
+ CompositorBridgeParent* mCompositorBridgeParent;
+ TimeStamp mLastCompose;
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ TimeStamp mExpectedComposeStartTime;
+#endif
+
+ bool mAsapScheduling;
+ bool mIsObservingVsync;
+ uint32_t mNeedsComposite;
+ int32_t mVsyncNotificationsSkipped;
+ widget::CompositorWidget* mWidget;
+ RefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
+
+ mozilla::Monitor mCurrentCompositeTaskMonitor;
+ RefPtr<CancelableRunnable> mCurrentCompositeTask;
+
+ mozilla::Monitor mSetNeedsCompositeMonitor;
+ RefPtr<CancelableRunnable> mSetNeedsCompositeTask;
+};
+
+class CompositorBridgeParentBase : public PCompositorBridgeParent,
+ public HostIPCAllocator,
+ public ShmemAllocator,
+ public MetricsSharingController
+{
+public:
+ virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const uint64_t& aTransactionId,
+ const TargetConfig& aTargetConfig,
+ const InfallibleTArray<PluginWindowData>& aPlugins,
+ bool aIsFirstPaint,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ int32_t aPaintSyncId,
+ bool aHitTestUpdate) = 0;
+
+ virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
+
+ virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) { }
+
+ virtual void ForceComposite(LayerTransactionParent* aLayerTree) { }
+ virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
+ const TimeStamp& aTime) { return true; }
+ virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) { }
+ virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree) = 0;
+ virtual void FlushApzRepaints(const LayerTransactionParent* aLayerTree) = 0;
+ virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
+ APZTestData* aOutData) { }
+ virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
+ const uint64_t& aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets) = 0;
+ virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) {}
+
+ virtual ShmemAllocator* AsShmemAllocator() override { return this; }
+
+ virtual bool RecvSyncWithCompositor() override { return true; }
+
+ // HostIPCAllocator
+ virtual base::ProcessId GetChildProcessId() override;
+ virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
+ virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
+
+ // ShmemAllocator
+ virtual bool AllocShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aType,
+ mozilla::ipc::Shmem* aShmem) override;
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aType,
+ mozilla::ipc::Shmem* aShmem) override;
+ virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
+ // MetricsSharingController
+ NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return HostIPCAllocator::AddRef(); }
+ NS_IMETHOD_(MozExternalRefCountType) Release() override { return HostIPCAllocator::Release(); }
+ base::ProcessId RemotePid() override;
+ bool StartSharingMetrics(mozilla::ipc::SharedMemoryBasic::Handle aHandle,
+ CrossProcessMutexHandle aMutexHandle,
+ uint64_t aLayersId,
+ uint32_t aApzcId) override;
+ bool StopSharingMetrics(FrameMetrics::ViewID aScrollId,
+ uint32_t aApzcId) override;
+};
+
+class CompositorBridgeParent final : public CompositorBridgeParentBase
+ , public CompositorController
+{
+ friend class CompositorVsyncScheduler;
+ friend class CompositorThreadHolder;
+ friend class InProcessCompositorSession;
+ friend class gfx::GPUProcessManager;
+ friend class gfx::GPUParent;
+
+public:
+ NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return CompositorBridgeParentBase::AddRef(); }
+ NS_IMETHOD_(MozExternalRefCountType) Release() override { return CompositorBridgeParentBase::Release(); }
+
+ explicit CompositorBridgeParent(CSSToLayoutDeviceScale aScale,
+ const TimeDuration& aVsyncRate,
+ bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize);
+
+ // Must only be called by CompositorBridgeChild. After invoking this, the
+ // IPC channel is active and RecvWillStop/ActorDestroy must be called to
+ // free the compositor.
+ void InitSameProcess(widget::CompositorWidget* aWidget,
+ const uint64_t& aLayerTreeId,
+ bool aUseAPZ);
+
+ // Must only be called by GPUParent. After invoking this, the IPC channel
+ // is active and RecvWillStop/ActorDestroy must be called to free the
+ // compositor.
+ bool Bind(Endpoint<PCompositorBridgeParent>&& aEndpoint);
+
+ virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override;
+ virtual bool RecvReset(nsTArray<LayersBackend>&& aBackendHints, bool* aResult, TextureFactoryIdentifier* aOutIdentifier) override;
+ virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override;
+ virtual bool RecvRequestOverfill() override;
+ virtual bool RecvWillClose() override;
+ virtual bool RecvPause() override;
+ virtual bool RecvResume() override;
+ virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
+ virtual bool RecvNotifyChildRecreated(const uint64_t& child) override;
+ virtual bool RecvAdoptChild(const uint64_t& child) override;
+ virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
+ const gfx::IntRect& aRect) override;
+ virtual bool RecvFlushRendering() override;
+ virtual bool RecvForcePresent() override;
+
+ virtual bool RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId) override {
+ MOZ_ASSERT_UNREACHABLE("This message is only sent cross-process");
+ return true;
+ }
+
+ virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override;
+ virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override;
+ virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override;
+
+ // Unused for chrome <-> compositor communication (which this class does).
+ // @see CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint
+ virtual bool RecvRequestNotifyAfterRemotePaint() override { return true; };
+
+ virtual bool RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+ const uint32_t& aPresShellId) override;
+ void ClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+ const Maybe<uint32_t>& aPresShellId);
+ virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+ const CSSIntRegion& aRegion) override;
+
+ virtual bool RecvAllPluginsCaptured() override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const uint64_t& aTransactionId,
+ const TargetConfig& aTargetConfig,
+ const InfallibleTArray<PluginWindowData>& aPlugins,
+ bool aIsFirstPaint,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ int32_t aPaintSyncId,
+ bool aHitTestUpdate) override;
+ virtual void ForceComposite(LayerTransactionParent* aLayerTree) override;
+ virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
+ const TimeStamp& aTime) override;
+ virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) override;
+ virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
+ override;
+ virtual void FlushApzRepaints(const LayerTransactionParent* aLayerTree) override;
+ virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
+ APZTestData* aOutData) override;
+ virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
+ const uint64_t& aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets) override;
+ virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) override { return mCompositionManager; }
+
+ virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aId,
+ const uint64_t& aSerial) override;
+ virtual bool DeallocPTextureParent(PTextureParent* actor) override;
+
+ virtual bool IsSameProcess() const override;
+
+
+ PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override;
+ bool DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) override;
+
+ /**
+ * Request that the compositor be recreated due to a shared device reset.
+ * This must be called on the main thread, and blocks until a task posted
+ * to the compositor thread has completed.
+ *
+ * Note that this posts a task directly, rather than using synchronous
+ * IPDL, and waits on a monitor notification from the compositor thread.
+ * We do this as a best-effort attempt to jump any IPDL messages that
+ * have not yet been posted (and are sitting around in the IO pipe), to
+ * minimize the amount of time the main thread is blocked.
+ */
+ bool ResetCompositor(const nsTArray<LayersBackend>& aBackendHints,
+ TextureFactoryIdentifier* aOutIdentifier);
+
+ /**
+ * This forces the is-first-paint flag to true. This is intended to
+ * be called by the widget code when it loses its viewport information
+ * (or for whatever reason wants to refresh the viewport information).
+ * The information refresh happens because the compositor will call
+ * SetFirstPaintViewport on the next frame of composition.
+ */
+ void ForceIsFirstPaint();
+
+ static void SetShadowProperties(Layer* aLayer);
+
+ void NotifyChildCreated(uint64_t aChild);
+
+ void AsyncRender();
+
+ // Can be called from any thread
+ void ScheduleRenderOnCompositorThread() override;
+ void SchedulePauseOnCompositorThread();
+ void InvalidateOnCompositorThread();
+ /**
+ * Returns true if a surface was obtained and the resume succeeded; false
+ * otherwise.
+ */
+ bool ScheduleResumeOnCompositorThread();
+ bool ScheduleResumeOnCompositorThread(int width, int height);
+
+ virtual void ScheduleComposition();
+ void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint,
+ bool aScheduleComposite, uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction, bool aHitTestUpdate);
+
+ void UpdatePaintTime(LayerTransactionParent* aLayerTree,
+ const TimeDuration& aPaintTime) override;
+
+ /**
+ * Check rotation info and schedule a rendering task if needed.
+ * Only can be called from compositor thread.
+ */
+ void ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, bool aIsFirstPaint);
+
+ /**
+ * Returns the unique layer tree identifier that corresponds to the root
+ * tree of this compositor.
+ */
+ uint64_t RootLayerTreeId();
+
+ /**
+ * Notify local and remote layer trees connected to this compositor that
+ * the compositor's local device is being reset. All layers must be
+ * invalidated to clear any cached TextureSources.
+ *
+ * This must be called on the compositor thread.
+ */
+ void InvalidateRemoteLayers();
+
+ /**
+ * Returns a pointer to the CompositorBridgeParent corresponding to the given ID.
+ */
+ static CompositorBridgeParent* GetCompositorBridgeParent(uint64_t id);
+
+ /**
+ * Notify the compositor for the given layer tree that vsync has occurred.
+ */
+ static void NotifyVsync(const TimeStamp& aTimeStamp, const uint64_t& aLayersId);
+
+ /**
+ * Set aController as the pan/zoom callback for the subtree referred
+ * to by aLayersId.
+ *
+ * Must run on content main thread.
+ */
+ static void SetControllerForLayerTree(uint64_t aLayersId,
+ GeckoContentController* aController);
+
+ /**
+ * A new child process has been configured to push transactions
+ * directly to us. Transport is to its thread context.
+ */
+ static bool
+ CreateForContent(Endpoint<PCompositorBridgeParent>&& aEndpoint);
+
+ struct LayerTreeState {
+ LayerTreeState();
+ ~LayerTreeState();
+ RefPtr<Layer> mRoot;
+ RefPtr<GeckoContentController> mController;
+ APZCTreeManagerParent* mApzcTreeManagerParent;
+ CompositorBridgeParent* mParent;
+ LayerManagerComposite* mLayerManager;
+ // Pointer to the CrossProcessCompositorBridgeParent. Used by APZCs to share
+ // their FrameMetrics with the corresponding child process that holds
+ // the PCompositorBridgeChild
+ CrossProcessCompositorBridgeParent* mCrossProcessParent;
+ TargetConfig mTargetConfig;
+ APZTestData mApzTestData;
+ LayerTransactionParent* mLayerTree;
+ nsTArray<PluginWindowData> mPluginData;
+ bool mUpdatedPluginDataAvailable;
+
+ // Number of times the compositor has been reset without having been
+ // acknowledged by the child.
+ uint32_t mPendingCompositorUpdates;
+
+ CompositorController* GetCompositorController() const;
+ MetricsSharingController* CrossProcessSharingController() const;
+ MetricsSharingController* InProcessSharingController() const;
+ };
+
+ /**
+ * Lookup the indirect shadow tree for |aId| and return it if it
+ * exists. Otherwise null is returned. This must only be called on
+ * the compositor thread.
+ */
+ static LayerTreeState* GetIndirectShadowTree(uint64_t aId);
+
+ /**
+ * Given the layers id for a content process, get the APZCTreeManagerParent
+ * for the corresponding *root* layers id. That is, the APZCTreeManagerParent,
+ * if one is found, will always be connected to the parent process rather
+ * than a content process. Note that unless the compositor process is
+ * separated this is expected to return null, because if the compositor is
+ * living in the gecko parent process then there is no APZCTreeManagerParent
+ * for the parent process.
+ */
+ static APZCTreeManagerParent* GetApzcTreeManagerParentForRoot(
+ uint64_t aContentLayersId);
+ /**
+ * Same as the GetApzcTreeManagerParentForRoot function, but returns
+ * the GeckoContentController for the parent process.
+ */
+ static GeckoContentController* GetGeckoContentControllerForRoot(
+ uint64_t aContentLayersId);
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ /**
+ * Calculates and requests the main thread update plugin positioning, clip,
+ * and visibility via ipc.
+ */
+ bool UpdatePluginWindowState(uint64_t aId);
+
+ /**
+ * Plugin visibility helpers for the apz (main thread) and compositor
+ * thread.
+ */
+ void ScheduleShowAllPluginWindows() override;
+ void ScheduleHideAllPluginWindows() override;
+ void ShowAllPluginWindows();
+ void HideAllPluginWindows();
+#else
+ void ScheduleShowAllPluginWindows() override {}
+ void ScheduleHideAllPluginWindows() override {}
+#endif
+
+ /**
+ * Main thread response for a plugin visibility request made by the
+ * compositor thread.
+ */
+ virtual bool RecvRemotePluginsReady() override;
+
+ /**
+ * Used by the profiler to denote when a vsync occured
+ */
+ static void PostInsertVsyncProfilerMarker(mozilla::TimeStamp aVsyncTimestamp);
+
+ widget::CompositorWidget* GetWidget() { return mWidget; }
+
+ void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
+
+ PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
+ bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
+
+ PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
+ bool DeallocPAPZParent(PAPZParent* aActor) override;
+
+ bool RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ) override;
+
+ RefPtr<APZCTreeManager> GetAPZCTreeManager();
+
+ bool AsyncPanZoomEnabled() const {
+ return !!mApzcTreeManager;
+ }
+
+private:
+
+ void Initialize();
+
+ /**
+ * Called during destruction in order to release resources as early as possible.
+ */
+ void StopAndClearResources();
+
+ /**
+ * This returns a reference to the APZCTreeManager to which
+ * pan/zoom-related events can be sent.
+ */
+ static already_AddRefed<APZCTreeManager> GetAPZCTreeManager(uint64_t aLayersId);
+
+ /**
+ * Release compositor-thread resources referred to by |aID|.
+ *
+ * Must run on the content main thread.
+ */
+ static void DeallocateLayerTreeId(uint64_t aId);
+
+protected:
+ // Protected destructor, to discourage deletion outside of Release():
+ virtual ~CompositorBridgeParent();
+
+ void DeferredDestroy();
+
+ virtual PLayerTransactionParent*
+ AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
+ const uint64_t& aId,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ bool* aSuccess) override;
+ virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override;
+ virtual void ScheduleTask(already_AddRefed<CancelableRunnable>, int);
+ void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
+
+ void SetEGLSurfaceSize(int width, int height);
+
+ void InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints);
+ void PauseComposition();
+ void ResumeComposition();
+ void ResumeCompositionAndResize(int width, int height);
+ void ForceComposition();
+ void CancelCurrentCompositeTask();
+ void Invalidate();
+ bool IsPendingComposite();
+ void FinishPendingComposite();
+
+ RefPtr<Compositor> NewCompositor(const nsTArray<LayersBackend>& aBackendHints);
+ void ResetCompositorTask(const nsTArray<LayersBackend>& aBackendHints,
+ Maybe<TextureFactoryIdentifier>* aOutNewIdentifier);
+ Maybe<TextureFactoryIdentifier> ResetCompositorImpl(const nsTArray<LayersBackend>& aBackendHints);
+
+ /**
+ * Add a compositor to the global compositor map.
+ */
+ static void AddCompositor(CompositorBridgeParent* compositor, uint64_t* id);
+ /**
+ * Remove a compositor from the global compositor map.
+ */
+ static CompositorBridgeParent* RemoveCompositor(uint64_t id);
+
+ /**
+ * Creates the global compositor map.
+ */
+ static void Setup();
+
+ /**
+ * Destroys the compositor thread and global compositor map.
+ */
+ static void Shutdown();
+
+ /**
+ * Finish the shutdown operation on the compositor thread.
+ */
+ static void FinishShutdown();
+
+ /**
+ * Return true if current state allows compositing, that is
+ * finishing a layers transaction.
+ */
+ bool CanComposite();
+
+ void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
+
+ // The indirect layer tree lock must be held before calling this function.
+ // Callback should take (LayerTreeState* aState, const uint64_t& aLayersId)
+ template <typename Lambda>
+ inline void ForEachIndirectLayerTree(const Lambda& aCallback);
+
+ RefPtr<LayerManagerComposite> mLayerManager;
+ RefPtr<Compositor> mCompositor;
+ RefPtr<AsyncCompositionManager> mCompositionManager;
+ widget::CompositorWidget* mWidget;
+ TimeStamp mTestTime;
+ CSSToLayoutDeviceScale mScale;
+ TimeDuration mVsyncRate;
+ bool mIsTesting;
+
+ uint64_t mPendingTransaction;
+
+ bool mPaused;
+
+ bool mUseExternalSurfaceSize;
+ gfx::IntSize mEGLSurfaceSize;
+
+ mozilla::Monitor mPauseCompositionMonitor;
+ mozilla::Monitor mResumeCompositionMonitor;
+ mozilla::Monitor mResetCompositorMonitor;
+
+ uint64_t mCompositorID;
+ uint64_t mRootLayerTreeID;
+
+ bool mOverrideComposeReadiness;
+ RefPtr<CancelableRunnable> mForceCompositionTask;
+
+ RefPtr<APZCTreeManager> mApzcTreeManager;
+
+ RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+ RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
+ // This makes sure the compositorParent is not destroyed before receiving
+ // confirmation that the channel is closed.
+ // mSelfRef is cleared in DeferredDestroy which is scheduled by ActorDestroy.
+ RefPtr<CompositorBridgeParent> mSelfRef;
+
+ TimeDuration mPaintTime;
+
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+ // cached plugin data used to reduce the number of updates we request.
+ uint64_t mLastPluginUpdateLayerTreeId;
+ nsIntPoint mPluginsLayerOffset;
+ nsIntRegion mPluginsLayerVisibleRegion;
+ nsTArray<PluginWindowData> mCachedPluginData;
+ // Time until which we will block composition to wait for plugin updates.
+ TimeStamp mWaitForPluginsUntil;
+ // Indicates that we have actually blocked a composition waiting for plugins.
+ bool mHaveBlockedForPlugins = false;
+ // indicates if plugin window visibility and metric updates are currently
+ // being defered due to a scroll operation.
+ bool mDeferPluginWindows;
+ // indicates if the plugin windows were hidden, and need to be made
+ // visible again even if their geometry has not changed.
+ bool mPluginWindowsHidden;
+#endif
+
+ DISALLOW_EVIL_CONSTRUCTORS(CompositorBridgeParent);
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_CompositorBridgeParent_h
diff --git a/gfx/layers/ipc/CompositorThread.cpp b/gfx/layers/ipc/CompositorThread.cpp
new file mode 100644
index 000000000..789a5d5d3
--- /dev/null
+++ b/gfx/layers/ipc/CompositorThread.cpp
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=99 : */
+/* 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 "CompositorThread.h"
+#include "MainThreadUtils.h"
+#include "nsThreadUtils.h"
+#include "CompositorBridgeParent.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/media/MediaSystemResourceService.h"
+
+namespace mozilla {
+
+namespace gfx {
+// See VRManagerChild.cpp
+void ReleaseVRManagerParentSingleton();
+} // namespace gfx
+
+namespace layers {
+
+static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
+static bool sFinishedCompositorShutDown = false;
+
+// See ImageBridgeChild.cpp
+void ReleaseImageBridgeParentSingleton();
+
+CompositorThreadHolder* GetCompositorThreadHolder()
+{
+ return sCompositorThreadHolder;
+}
+
+base::Thread*
+CompositorThread()
+{
+ return sCompositorThreadHolder
+ ? sCompositorThreadHolder->GetCompositorThread()
+ : nullptr;
+}
+
+/* static */ MessageLoop*
+CompositorThreadHolder::Loop()
+{
+ return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
+}
+
+CompositorThreadHolder*
+CompositorThreadHolder::GetSingleton()
+{
+ return sCompositorThreadHolder;
+}
+
+CompositorThreadHolder::CompositorThreadHolder()
+ : mCompositorThread(CreateCompositorThread())
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_COUNT_CTOR(CompositorThreadHolder);
+}
+
+CompositorThreadHolder::~CompositorThreadHolder()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MOZ_COUNT_DTOR(CompositorThreadHolder);
+
+ DestroyCompositorThread(mCompositorThread);
+}
+
+/* static */ void
+CompositorThreadHolder::DestroyCompositorThread(base::Thread* aCompositorThread)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
+
+ CompositorBridgeParent::Shutdown();
+ delete aCompositorThread;
+ sFinishedCompositorShutDown = true;
+}
+
+/* static */ base::Thread*
+CompositorThreadHolder::CreateCompositorThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
+
+ base::Thread* compositorThread = new base::Thread("Compositor");
+
+ base::Thread::Options options;
+ /* Timeout values are powers-of-two to enable us get better data.
+ 128ms is chosen for transient hangs because 8Hz should be the minimally
+ acceptable goal for Compositor responsiveness (normal goal is 60Hz). */
+ options.transient_hang_timeout = 128; // milliseconds
+ /* 2048ms is chosen for permanent hangs because it's longer than most
+ * Compositor hangs seen in the wild, but is short enough to not miss getting
+ * native hang stacks. */
+ options.permanent_hang_timeout = 2048; // milliseconds
+#if defined(_WIN32)
+ /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As
+ * such the thread is a gui thread, and must process a windows message queue or
+ * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */
+ options.message_loop_type = MessageLoop::TYPE_UI;
+#endif
+
+ if (!compositorThread->StartWithOptions(options)) {
+ delete compositorThread;
+ return nullptr;
+ }
+
+ CompositorBridgeParent::Setup();
+ ImageBridgeParent::Setup();
+
+ return compositorThread;
+}
+
+void
+CompositorThreadHolder::Start()
+{
+ MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
+ MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
+
+ sCompositorThreadHolder = new CompositorThreadHolder();
+}
+
+void
+CompositorThreadHolder::Shutdown()
+{
+ MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
+ MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
+
+ ReleaseImageBridgeParentSingleton();
+ gfx::ReleaseVRManagerParentSingleton();
+ MediaSystemResourceService::Shutdown();
+
+ sCompositorThreadHolder = nullptr;
+
+ // No locking is needed around sFinishedCompositorShutDown because it is only
+ // ever accessed on the main thread.
+ while (!sFinishedCompositorShutDown) {
+ NS_ProcessNextEvent(nullptr, true);
+ }
+
+ CompositorBridgeParent::FinishShutdown();
+}
+
+/* static */ bool
+CompositorThreadHolder::IsInCompositorThread()
+{
+ return CompositorThread() &&
+ CompositorThread()->thread_id() == PlatformThread::CurrentId();
+}
+
+} // namespace mozilla
+} // namespace layers
diff --git a/gfx/layers/ipc/CompositorThread.h b/gfx/layers/ipc/CompositorThread.h
new file mode 100644
index 000000000..cc47f5fa2
--- /dev/null
+++ b/gfx/layers/ipc/CompositorThread.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=99 : */
+/* 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_CompositorThread_h
+#define mozilla_layers_CompositorThread_h
+
+#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS
+#include "base/platform_thread.h" // for PlatformThreadId
+#include "base/thread.h" // for Thread
+#include "base/message_loop.h"
+#include "nsISupportsImpl.h"
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+
+namespace mozilla {
+namespace layers {
+
+class CompositorThreadHolder final
+{
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
+
+public:
+ CompositorThreadHolder();
+
+ base::Thread* GetCompositorThread() const {
+ return mCompositorThread;
+ }
+
+ static CompositorThreadHolder* GetSingleton();
+
+ static bool IsActive() {
+ return !!GetSingleton();
+ }
+
+ /**
+ * Creates the compositor thread and the global compositor map.
+ */
+ static void Start();
+
+ /*
+ * Waits for all [CrossProcess]CompositorBridgeParents to shutdown and
+ * releases compositor-thread owned resources.
+ */
+ static void Shutdown();
+
+ static MessageLoop* Loop();
+
+ // Returns true if the calling thread is the compositor thread.
+ static bool IsInCompositorThread();
+
+private:
+ ~CompositorThreadHolder();
+
+ base::Thread* const mCompositorThread;
+
+ static base::Thread* CreateCompositorThread();
+ static void DestroyCompositorThread(base::Thread* aCompositorThread);
+
+ friend class CompositorBridgeParent;
+};
+
+base::Thread* CompositorThread();
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_CompositorThread_h
diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
new file mode 100644
index 000000000..1bb6d046b
--- /dev/null
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -0,0 +1,578 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et 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 "mozilla/layers/CrossProcessCompositorBridgeParent.h"
+#include <stdio.h> // for fprintf, stdout
+#include <stdint.h> // for uint64_t
+#include <map> // for _Rb_tree_iterator, etc
+#include <utility> // for pair
+#include "LayerTransactionParent.h" // for LayerTransactionParent
+#include "RenderTrace.h" // for RenderTraceLayers
+#include "base/message_loop.h" // for MessageLoop
+#include "base/process.h" // for ProcessId
+#include "base/task.h" // for CancelableTask, etc
+#include "base/thread.h" // for Thread
+#include "gfxContext.h" // for gfxContext
+#include "gfxPlatform.h" // for gfxPlatform
+#include "TreeTraversal.h" // for ForEachNode
+#ifdef MOZ_WIDGET_GTK
+#include "gfxPlatformGtk.h" // for gfxPlatform
+#endif
+#include "gfxPrefs.h" // for gfxPrefs
+#include "mozilla/AutoRestore.h" // for AutoRestore
+#include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown
+#include "mozilla/DebugOnly.h" // for DebugOnly
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/gfx/2D.h" // for DrawTarget
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/gfx/Rect.h" // for IntSize
+#include "VRManager.h" // for VRManager
+#include "mozilla/ipc/Transport.h" // for Transport
+#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
+#include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
+#include "mozilla/layers/APZThreadUtils.h" // for APZCTreeManager
+#include "mozilla/layers/AsyncCompositionManager.h"
+#include "mozilla/layers/BasicCompositor.h" // for BasicCompositor
+#include "mozilla/layers/Compositor.h" // for Compositor
+#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/FrameUniformityData.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/LayerTreeOwnerTracker.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "mozilla/layers/PLayerTransactionParent.h"
+#include "mozilla/layers/RemoteContentController.h"
+#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "mozilla/Telemetry.h"
+#ifdef MOZ_WIDGET_GTK
+#include "basic/X11BasicCompositor.h" // for X11BasicCompositor
+#endif
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsDebug.h" // for NS_ASSERTION, etc
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "nsIWidget.h" // for nsIWidget
+#include "nsTArray.h" // for nsTArray
+#include "nsThreadUtils.h" // for NS_IsMainThread
+#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
+#ifdef XP_WIN
+#include "mozilla/layers/CompositorD3D11.h"
+#include "mozilla/layers/CompositorD3D9.h"
+#endif
+#include "GeckoProfiler.h"
+#include "mozilla/ipc/ProtocolTypes.h"
+#include "mozilla/Unused.h"
+#include "mozilla/Hal.h"
+#include "mozilla/HalTypes.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Telemetry.h"
+#ifdef MOZ_ENABLE_PROFILER_SPS
+#include "ProfilerMarkers.h"
+#endif
+#include "mozilla/VsyncDispatcher.h"
+#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+#include "VsyncSource.h"
+#endif
+#include "mozilla/widget/CompositorWidget.h"
+#ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
+# include "mozilla/widget/CompositorWidgetParent.h"
+#endif
+
+#include "LayerScope.h"
+
+namespace mozilla {
+
+namespace layers {
+
+// defined in CompositorBridgeParent.cpp
+typedef map<uint64_t, CompositorBridgeParent::LayerTreeState> LayerTreeMap;
+extern LayerTreeMap sIndirectLayerTrees;
+extern StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock;
+
+bool
+CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint()
+{
+ mNotifyAfterRemotePaint = true;
+ return true;
+}
+
+void
+CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ // We must keep this object alive untill the code handling message
+ // reception is finished on this thread.
+ MessageLoop::current()->PostTask(NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy));
+}
+
+PLayerTransactionParent*
+CrossProcessCompositorBridgeParent::AllocPLayerTransactionParent(
+ const nsTArray<LayersBackend>&,
+ const uint64_t& aId,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ bool *aSuccess)
+{
+ MOZ_ASSERT(aId != 0);
+
+ // 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->mCrossProcessParent = this;
+ LayerManagerComposite* lm = state->mLayerManager;
+ *aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier();
+ *aSuccess = true;
+ LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId);
+ p->AddIPDLReference();
+ sIndirectLayerTrees[aId].mLayerTree = p;
+ p->SetPendingCompositorUpdates(state->mPendingCompositorUpdates);
+ return p;
+ }
+
+ NS_WARNING("Created child without a matching parent?");
+ *aSuccess = false;
+ LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId);
+ p->AddIPDLReference();
+ return p;
+}
+
+bool
+CrossProcessCompositorBridgeParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers)
+{
+ LayerTransactionParent* slp = static_cast<LayerTransactionParent*>(aLayers);
+ EraseLayerState(slp->GetId());
+ static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference();
+ return true;
+}
+
+bool
+CrossProcessCompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
+{
+ // Check to see if this child process has access to this layer tree.
+ if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
+ NS_ERROR("Unexpected layers id in RecvAsyncPanZoomEnabled; dropping message...");
+ return false;
+ }
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
+
+ *aHasAPZ = state.mParent ? state.mParent->AsyncPanZoomEnabled() : false;
+ return true;
+}
+
+PAPZCTreeManagerParent*
+CrossProcessCompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId)
+{
+ // Check to see if this child process has access to this layer tree.
+ if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
+ NS_ERROR("Unexpected layers id in AllocPAPZCTreeManagerParent; dropping message...");
+ return nullptr;
+ }
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
+ MOZ_ASSERT(state.mParent);
+ MOZ_ASSERT(!state.mApzcTreeManagerParent);
+ state.mApzcTreeManagerParent = new APZCTreeManagerParent(aLayersId, state.mParent->GetAPZCTreeManager());
+
+ return state.mApzcTreeManagerParent;
+}
+bool
+CrossProcessCompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
+{
+ APZCTreeManagerParent* parent = static_cast<APZCTreeManagerParent*>(aActor);
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ auto iter = sIndirectLayerTrees.find(parent->LayersId());
+ if (iter != sIndirectLayerTrees.end()) {
+ CompositorBridgeParent::LayerTreeState& state = iter->second;
+ MOZ_ASSERT(state.mApzcTreeManagerParent == parent);
+ state.mApzcTreeManagerParent = nullptr;
+ }
+
+ delete parent;
+
+ return true;
+}
+
+PAPZParent*
+CrossProcessCompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
+{
+ // Check to see if this child process has access to this layer tree.
+ if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
+ NS_ERROR("Unexpected layers id in AllocPAPZParent; dropping message...");
+ return nullptr;
+ }
+
+ RemoteContentController* controller = new RemoteContentController();
+
+ // Increment the controller's refcount before we return it. This will keep the
+ // controller alive until it is released by IPDL in DeallocPAPZParent.
+ controller->AddRef();
+
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
+ MOZ_ASSERT(!state.mController);
+ state.mController = controller;
+
+ return controller;
+}
+
+bool
+CrossProcessCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
+{
+ RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
+ controller->Release();
+ return true;
+}
+
+bool
+CrossProcessCompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
+ it != sIndirectLayerTrees.end(); it++) {
+ CompositorBridgeParent::LayerTreeState* lts = &it->second;
+ if (lts->mParent && lts->mCrossProcessParent == this) {
+ lts->mParent->NotifyChildCreated(child);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+CrossProcessCompositorBridgeParent::ShadowLayersUpdated(
+ LayerTransactionParent* aLayerTree,
+ const uint64_t& aTransactionId,
+ const TargetConfig& aTargetConfig,
+ const InfallibleTArray<PluginWindowData>& aPlugins,
+ bool aIsFirstPaint,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ int32_t /*aPaintSyncId: unused*/,
+ bool aHitTestUpdate)
+{
+ uint64_t id = aLayerTree->GetId();
+
+ MOZ_ASSERT(id != 0);
+
+ CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return;
+ }
+ MOZ_ASSERT(state->mParent);
+ state->mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint);
+
+ Layer* shadowRoot = aLayerTree->GetRoot();
+ if (shadowRoot) {
+ CompositorBridgeParent::SetShadowProperties(shadowRoot);
+ }
+ UpdateIndirectTree(id, shadowRoot, aTargetConfig);
+
+ // Cache the plugin data for this remote layer tree
+ state->mPluginData = aPlugins;
+ state->mUpdatedPluginDataAvailable = true;
+
+ state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite,
+ aPaintSequenceNumber, aIsRepeatTransaction, aHitTestUpdate);
+
+ // Send the 'remote paint ready' message to the content thread if it has already asked.
+ if(mNotifyAfterRemotePaint) {
+ Unused << SendRemotePaintIsReady();
+ mNotifyAfterRemotePaint = false;
+ }
+
+ 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->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), true);
+ }
+
+ aLayerTree->SetPendingTransactionId(aTransactionId);
+}
+
+void
+CrossProcessCompositorBridgeParent::DidComposite(
+ uint64_t aId,
+ TimeStamp& aCompositeStart,
+ TimeStamp& aCompositeEnd)
+{
+ sIndirectLayerTreesLock->AssertCurrentThreadOwns();
+ if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
+ Unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
+ layerTree->SetPendingTransactionId(0);
+ }
+}
+
+void
+CrossProcessCompositorBridgeParent::ForceComposite(LayerTransactionParent* aLayerTree)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ CompositorBridgeParent* parent;
+ { // scope lock
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ parent = sIndirectLayerTrees[id].mParent;
+ }
+ if (parent) {
+ parent->ForceComposite(aLayerTree);
+ }
+}
+
+void
+CrossProcessCompositorBridgeParent::NotifyClearCachedResources(LayerTransactionParent* aLayerTree)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+
+ 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->SendObserveLayerUpdate(id, aLayerTree->GetChildEpoch(), false);
+ }
+}
+
+bool
+CrossProcessCompositorBridgeParent::SetTestSampleTime(
+ LayerTransactionParent* aLayerTree, const TimeStamp& aTime)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return false;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ return state->mParent->SetTestSampleTime(aLayerTree, aTime);
+}
+
+void
+CrossProcessCompositorBridgeParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ state->mParent->LeaveTestMode(aLayerTree);
+}
+
+void
+CrossProcessCompositorBridgeParent::ApplyAsyncProperties(
+ LayerTransactionParent* aLayerTree)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ state->mParent->ApplyAsyncProperties(aLayerTree);
+}
+
+void
+CrossProcessCompositorBridgeParent::FlushApzRepaints(const LayerTransactionParent* aLayerTree)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ state->mParent->FlushApzRepaints(aLayerTree);
+}
+
+void
+CrossProcessCompositorBridgeParent::GetAPZTestData(
+ const LayerTransactionParent* aLayerTree,
+ APZTestData* aOutData)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ *aOutData = sIndirectLayerTrees[id].mApzTestData;
+}
+
+void
+CrossProcessCompositorBridgeParent::SetConfirmedTargetAPZC(
+ const LayerTransactionParent* aLayerTree,
+ const uint64_t& aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state || !state->mParent) {
+ return;
+ }
+
+ state->mParent->SetConfirmedTargetAPZC(aLayerTree, aInputBlockId, aTargets);
+}
+
+AsyncCompositionManager*
+CrossProcessCompositorBridgeParent::GetCompositionManager(LayerTransactionParent* aLayerTree)
+{
+ uint64_t id = aLayerTree->GetId();
+ const CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(state->mParent);
+ return state->mParent->GetCompositionManager(aLayerTree);
+}
+
+bool
+CrossProcessCompositorBridgeParent::RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId)
+{
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[aLayersId];
+
+ if (LayerTransactionParent* ltp = state.mLayerTree) {
+ ltp->AcknowledgeCompositorUpdate();
+ }
+ MOZ_ASSERT(state.mPendingCompositorUpdates > 0);
+ state.mPendingCompositorUpdates--;
+ return true;
+}
+
+void
+CrossProcessCompositorBridgeParent::DeferredDestroy()
+{
+ mCompositorThreadHolder = nullptr;
+ mSelfRef = nullptr;
+}
+
+CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent()
+{
+ MOZ_ASSERT(XRE_GetIOMessageLoop());
+ MOZ_ASSERT(IToplevelProtocol::GetTransport());
+}
+
+PTextureParent*
+CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aId,
+ const uint64_t& aSerial)
+{
+ CompositorBridgeParent::LayerTreeState* state = nullptr;
+
+ LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId);
+ if (sIndirectLayerTrees.end() != itr) {
+ state = &itr->second;
+ }
+
+ TextureFlags flags = aFlags;
+
+ if (!state || state->mPendingCompositorUpdates) {
+ // The compositor was recreated, and we're receiving layers updates for a
+ // a layer manager that will soon be discarded or invalidated. We can't
+ // return null because this will mess up deserialization later and we'll
+ // kill the content process. Instead, we signal that the underlying
+ // TextureHost should not attempt to access the compositor.
+ flags |= TextureFlags::INVALID_COMPOSITOR;
+ } else if (state->mLayerManager && state->mLayerManager->GetCompositor() &&
+ aLayersBackend != state->mLayerManager->GetCompositor()->GetBackendType()) {
+ gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong";
+ }
+
+ return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+bool
+CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
+{
+ return TextureHost::DestroyIPDLActor(actor);
+}
+
+bool
+CrossProcessCompositorBridgeParent::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+bool
+CrossProcessCompositorBridgeParent::RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+ const uint32_t& aPresShellId)
+{
+ CompositorBridgeParent* parent;
+ { // scope lock
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ parent = sIndirectLayerTrees[aLayersId].mParent;
+ }
+ if (parent) {
+ parent->ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId));
+ }
+ return true;
+}
+
+bool
+CrossProcessCompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+ const CSSIntRegion& aRegion)
+{
+ CompositorBridgeParent* parent;
+ { // scope lock
+ MonitorAutoLock lock(*sIndirectLayerTreesLock);
+ parent = sIndirectLayerTrees[aGuid.mLayersId].mParent;
+ }
+ if (parent) {
+ return parent->RecvNotifyApproximatelyVisibleRegion(aGuid, aRegion);
+ }
+ return true;
+}
+
+void
+CrossProcessCompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime)
+{
+ uint64_t id = aLayerTree->GetId();
+ MOZ_ASSERT(id != 0);
+
+ CompositorBridgeParent::LayerTreeState* state =
+ CompositorBridgeParent::GetIndirectShadowTree(id);
+ if (!state || !state->mParent) {
+ return;
+ }
+
+ state->mParent->UpdatePaintTime(aLayerTree, aPaintTime);
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
new file mode 100644
index 000000000..399969950
--- /dev/null
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=2 et 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_CrossProcessCompositorBridgeParent_h
+#define mozilla_layers_CrossProcessCompositorBridgeParent_h
+
+#include "mozilla/layers/CompositorBridgeParent.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * This class handles layer updates pushed directly from child processes to
+ * the compositor thread. It's associated with a CompositorBridgeParent on the
+ * compositor thread. While it uses the PCompositorBridge protocol to manage
+ * these updates, it doesn't actually drive compositing itself. For that it
+ * hands off work to the CompositorBridgeParent it's associated with.
+ */
+class CrossProcessCompositorBridgeParent final : public CompositorBridgeParentBase
+{
+ friend class CompositorBridgeParent;
+
+public:
+ explicit CrossProcessCompositorBridgeParent()
+ : mNotifyAfterRemotePaint(false)
+ , mDestroyCalled(false)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ }
+
+ void Bind(Endpoint<PCompositorBridgeParent>&& aEndpoint) {
+ if (!aEndpoint.Bind(this)) {
+ return;
+ }
+ mSelfRef = this;
+ }
+
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ // FIXME/bug 774388: work out what shutdown protocol we need.
+ virtual bool RecvInitialize(const uint64_t& aRootLayerTreeId) override { return false; }
+ virtual bool RecvReset(nsTArray<LayersBackend>&& aBackendHints, bool* aResult, TextureFactoryIdentifier* aOutIdentifier) override { return false; }
+ virtual bool RecvRequestOverfill() override { return true; }
+ virtual bool RecvWillClose() override { return true; }
+ virtual bool RecvPause() override { return true; }
+ virtual bool RecvResume() override { return true; }
+ virtual bool RecvNotifyChildCreated(const uint64_t& child) override;
+ virtual bool RecvNotifyChildRecreated(const uint64_t& child) override { return false; }
+ virtual bool RecvAdoptChild(const uint64_t& child) override { return false; }
+ virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
+ const gfx::IntRect& aRect) override
+ { return true; }
+ virtual bool RecvFlushRendering() override { return true; }
+ virtual bool RecvForcePresent() override { return true; }
+ virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
+ virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
+ virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override { return true; }
+
+ virtual bool RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+ const uint32_t& aPresShellId) override;
+
+ virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+ const CSSIntRegion& aRegion) override;
+
+ virtual bool RecvAllPluginsCaptured() override { return true; }
+
+ virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override
+ {
+ // Don't support calculating frame uniformity on the child process and
+ // this is just a stub for now.
+ MOZ_ASSERT(false);
+ return true;
+ }
+
+ /**
+ * Tells this CompositorBridgeParent to send a message when the compositor has received the transaction.
+ */
+ virtual bool RecvRequestNotifyAfterRemotePaint() override;
+
+ virtual PLayerTransactionParent*
+ AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
+ const uint64_t& aId,
+ TextureFactoryIdentifier* aTextureFactoryIdentifier,
+ bool *aSuccess) override;
+
+ virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override;
+
+ virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+ const uint64_t& aTransactionId,
+ const TargetConfig& aTargetConfig,
+ const InfallibleTArray<PluginWindowData>& aPlugins,
+ bool aIsFirstPaint,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ int32_t /*aPaintSyncId: unused*/,
+ bool aHitTestUpdate) override;
+ virtual void ForceComposite(LayerTransactionParent* aLayerTree) override;
+ virtual void NotifyClearCachedResources(LayerTransactionParent* aLayerTree) override;
+ virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
+ const TimeStamp& aTime) override;
+ virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) override;
+ virtual void ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
+ override;
+ virtual void FlushApzRepaints(const LayerTransactionParent* aLayerTree) override;
+ virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
+ APZTestData* aOutData) override;
+ virtual void SetConfirmedTargetAPZC(const LayerTransactionParent* aLayerTree,
+ const uint64_t& aInputBlockId,
+ const nsTArray<ScrollableLayerGuid>& aTargets) override;
+
+ virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
+ virtual bool RecvRemotePluginsReady() override { return false; }
+ virtual bool RecvAcknowledgeCompositorUpdate(const uint64_t& aLayersId) override;
+
+ void DidComposite(uint64_t aId,
+ TimeStamp& aCompositeStart,
+ TimeStamp& aCompositeEnd);
+
+ virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aId,
+ const uint64_t& aSerial) override;
+
+ virtual bool DeallocPTextureParent(PTextureParent* actor) override;
+
+ virtual bool IsSameProcess() const override;
+
+ PCompositorWidgetParent* AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) override {
+ // Not allowed.
+ return nullptr;
+ }
+ bool DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) override {
+ // Not allowed.
+ return false;
+ }
+
+ virtual bool RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ) override;
+
+ virtual PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
+ virtual bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
+
+ virtual PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
+ virtual bool DeallocPAPZParent(PAPZParent* aActor) override;
+
+ virtual void UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) override;
+
+protected:
+ void OnChannelConnected(int32_t pid) override {
+ mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();
+ }
+private:
+ // Private destructor, to discourage deletion outside of Release():
+ virtual ~CrossProcessCompositorBridgeParent();
+
+ void DeferredDestroy();
+
+ // There can be many CPCPs, and IPDL-generated code doesn't hold a
+ // reference to top-level actors. So we hold a reference to
+ // ourself. This is released (deferred) in ActorDestroy().
+ RefPtr<CrossProcessCompositorBridgeParent> mSelfRef;
+
+ RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+ // If true, we should send a RemotePaintIsReady message when the layer transaction
+ // is received
+ bool mNotifyAfterRemotePaint;
+ bool mDestroyCalled;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_CrossProcessCompositorBridgeParent_h
diff --git a/gfx/layers/ipc/GonkNativeHandle.cpp b/gfx/layers/ipc/GonkNativeHandle.cpp
new file mode 100644
index 000000000..8f808e623
--- /dev/null
+++ b/gfx/layers/ipc/GonkNativeHandle.cpp
@@ -0,0 +1,80 @@
+/* -*- 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 <unistd.h>
+
+#include "GonkNativeHandle.h"
+
+using namespace mozilla::layers;
+
+namespace mozilla {
+namespace layers {
+
+GonkNativeHandle::GonkNativeHandle()
+ : mNhObj(new NhObj())
+{
+}
+
+GonkNativeHandle::GonkNativeHandle(NhObj* aNhObj)
+ : mNhObj(aNhObj)
+{
+ MOZ_ASSERT(aNhObj);
+}
+
+
+void
+GonkNativeHandle::TransferToAnother(GonkNativeHandle& aHandle)
+{
+ aHandle.mNhObj = this->GetAndResetNhObj();
+}
+
+already_AddRefed<GonkNativeHandle::NhObj>
+GonkNativeHandle::GetAndResetNhObj()
+{
+ RefPtr<NhObj> nhObj = mNhObj;
+ mNhObj = new NhObj();
+ return nhObj.forget();
+}
+
+already_AddRefed<GonkNativeHandle::NhObj>
+GonkNativeHandle::GetDupNhObj()
+{
+ if (!IsValid()) {
+ return GonkNativeHandle::CreateDupNhObj(nullptr);
+ }
+ return GonkNativeHandle::CreateDupNhObj(mNhObj->mHandle);
+}
+
+/* static */ already_AddRefed<GonkNativeHandle::NhObj>
+GonkNativeHandle::CreateDupNhObj(native_handle_t* aHandle)
+{
+ RefPtr<NhObj> nhObj;
+ if (aHandle) {
+ native_handle* nativeHandle =
+ native_handle_create(aHandle->numFds, aHandle->numInts);
+ if (!nativeHandle) {
+ nhObj = new GonkNativeHandle::NhObj();
+ return nhObj.forget();
+ }
+
+ for (int i = 0; i < aHandle->numFds; ++i) {
+ nativeHandle->data[i] = dup(aHandle->data[i]);
+ }
+
+ memcpy(nativeHandle->data + nativeHandle->numFds,
+ aHandle->data + aHandle->numFds,
+ sizeof(int) * aHandle->numInts);
+
+ nhObj = new GonkNativeHandle::NhObj(nativeHandle);
+ } else {
+ nhObj = new GonkNativeHandle::NhObj();
+ }
+ return nhObj.forget();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/GonkNativeHandle.h b/gfx/layers/ipc/GonkNativeHandle.h
new file mode 100644
index 000000000..6afaea540
--- /dev/null
+++ b/gfx/layers/ipc/GonkNativeHandle.h
@@ -0,0 +1,24 @@
+/* -*- 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/. */
+
+#ifndef IPC_GonkNativeHandle_h
+#define IPC_GonkNativeHandle_h
+
+#include "mozilla/RefPtr.h" // for RefPtr
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace layers {
+
+struct GonkNativeHandle {
+ bool operator==(const GonkNativeHandle&) const { return false; }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // IPC_GonkNativeHandle_h
diff --git a/gfx/layers/ipc/GonkNativeHandleUtils.cpp b/gfx/layers/ipc/GonkNativeHandleUtils.cpp
new file mode 100644
index 000000000..fb2efecb3
--- /dev/null
+++ b/gfx/layers/ipc/GonkNativeHandleUtils.cpp
@@ -0,0 +1,93 @@
+/* -*- 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 "GonkNativeHandleUtils.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
+
+using namespace mozilla::layers;
+
+namespace IPC {
+
+namespace {
+
+class native_handle_Delete
+{
+public:
+ void operator()(native_handle* aNativeHandle) const
+ {
+ native_handle_close(aNativeHandle); // closes file descriptors
+ native_handle_delete(aNativeHandle);
+ }
+};
+
+} // anonymous namespace
+
+void
+ParamTraits<GonkNativeHandle>::Write(Message* aMsg,
+ const paramType& aParam)
+{
+ GonkNativeHandle handle = aParam;
+ MOZ_ASSERT(handle.IsValid());
+
+ RefPtr<GonkNativeHandle::NhObj> nhObj = handle.GetAndResetNhObj();
+ native_handle_t* nativeHandle = nhObj->GetAndResetNativeHandle();
+
+ size_t nbytes = nativeHandle->numInts * sizeof(int);
+ aMsg->WriteSize(nbytes);
+ aMsg->WriteBytes((nativeHandle->data + nativeHandle->numFds), nbytes);
+
+ for (size_t i = 0; i < static_cast<size_t>(nativeHandle->numFds); ++i) {
+ aMsg->WriteFileDescriptor(base::FileDescriptor(nativeHandle->data[i], true));
+ }
+}
+
+bool
+ParamTraits<GonkNativeHandle>::Read(const Message* aMsg,
+ PickleIterator* aIter, paramType* aResult)
+{
+ size_t nbytes;
+ if (!aMsg->ReadSize(aIter, &nbytes)) {
+ return false;
+ }
+
+ if (nbytes % sizeof(int) != 0) {
+ return false;
+ }
+
+ size_t numInts = nbytes / sizeof(int);
+ size_t numFds = aMsg->num_fds();
+ mozilla::UniquePtr<native_handle, native_handle_Delete> nativeHandle(
+ native_handle_create(numFds, numInts));
+ if (!nativeHandle) {
+ return false;
+ }
+
+ auto data =
+ reinterpret_cast<char*>(nativeHandle->data + nativeHandle->numFds);
+ if (!aMsg->ReadBytesInto(aIter, data, nbytes)) {
+ return false;
+ }
+
+ for (size_t i = 0; i < numFds; ++i) {
+ base::FileDescriptor fd;
+ if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
+ return false;
+ }
+ nativeHandle->data[i] = fd.fd;
+ nativeHandle->numFds = i + 1; // set number of valid file descriptors
+ }
+
+ GonkNativeHandle handle(new GonkNativeHandle::NhObj(nativeHandle.get()));
+ handle.TransferToAnother(*aResult);
+
+ mozilla::Unused << nativeHandle.release();
+
+ return true;
+}
+
+} // namespace IPC
diff --git a/gfx/layers/ipc/GonkNativeHandleUtils.h b/gfx/layers/ipc/GonkNativeHandleUtils.h
new file mode 100644
index 000000000..d91792c95
--- /dev/null
+++ b/gfx/layers/ipc/GonkNativeHandleUtils.h
@@ -0,0 +1,26 @@
+/* -*- 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/. */
+
+#ifndef IPC_GonkNativeHandleUtils_h
+#define IPC_GonkNativeHandleUtils_h
+
+#include "ipc/IPCMessageUtils.h"
+
+#include "GonkNativeHandle.h"
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::layers::GonkNativeHandle> {
+ typedef mozilla::layers::GonkNativeHandle paramType;
+ static void Write(Message*, const paramType&) {}
+ static bool Read(const Message*, PickleIterator*, paramType*) { return false; }
+};
+
+} // namespace IPC
+
+#endif // IPC_GonkNativeHandleUtils_h
diff --git a/gfx/layers/ipc/ISurfaceAllocator.cpp b/gfx/layers/ipc/ISurfaceAllocator.cpp
new file mode 100644
index 000000000..57da4d9cd
--- /dev/null
+++ b/gfx/layers/ipc/ISurfaceAllocator.cpp
@@ -0,0 +1,235 @@
+/* -*- 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 "ISurfaceAllocator.h"
+
+#include "gfxPrefs.h"
+#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
+#include "mozilla/layers/TextureHost.h" // for TextureHost
+#include "mozilla/layers/TextureForwarder.h"
+
+namespace mozilla {
+namespace layers {
+
+NS_IMPL_ISUPPORTS(GfxMemoryImageReporter, nsIMemoryReporter)
+
+mozilla::Atomic<ptrdiff_t> GfxMemoryImageReporter::sAmount(0);
+
+mozilla::ipc::SharedMemory::SharedMemoryType OptimalShmemType()
+{
+ return ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
+}
+
+void
+HostIPCAllocator::SendPendingAsyncMessages()
+{
+ if (mPendingAsyncMessage.empty()) {
+ return;
+ }
+
+ // Some type of AsyncParentMessageData message could have
+ // one file descriptor (e.g. OpDeliverFence).
+ // A number of file descriptors per gecko ipc message have a limitation
+ // on OS_POSIX (MACOSX or LINUX).
+#if defined(OS_POSIX)
+ static const uint32_t kMaxMessageNumber = FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE;
+#else
+ // default number that works everywhere else
+ static const uint32_t kMaxMessageNumber = 250;
+#endif
+
+ InfallibleTArray<AsyncParentMessageData> messages;
+ messages.SetCapacity(mPendingAsyncMessage.size());
+ for (size_t i = 0; i < mPendingAsyncMessage.size(); i++) {
+ messages.AppendElement(mPendingAsyncMessage[i]);
+ // Limit maximum number of messages.
+ if (messages.Length() >= kMaxMessageNumber) {
+ SendAsyncMessage(messages);
+ // Initialize Messages.
+ messages.Clear();
+ }
+ }
+
+ if (messages.Length() > 0) {
+ SendAsyncMessage(messages);
+ }
+ mPendingAsyncMessage.clear();
+}
+
+// XXX - We should actually figure out the minimum shmem allocation size on
+// a certain platform and use that.
+const uint32_t sShmemPageSize = 4096;
+
+#ifdef DEBUG
+const uint32_t sSupportedBlockSize = 4;
+#endif
+
+FixedSizeSmallShmemSectionAllocator::FixedSizeSmallShmemSectionAllocator(LayersIPCChannel* aShmProvider)
+: mShmProvider(aShmProvider)
+{
+ MOZ_ASSERT(mShmProvider);
+}
+
+FixedSizeSmallShmemSectionAllocator::~FixedSizeSmallShmemSectionAllocator()
+{
+ ShrinkShmemSectionHeap();
+}
+
+bool
+FixedSizeSmallShmemSectionAllocator::IPCOpen() const
+{
+ return mShmProvider->IPCOpen();
+}
+
+bool
+FixedSizeSmallShmemSectionAllocator::AllocShmemSection(uint32_t aSize, ShmemSection* aShmemSection)
+{
+ // For now we only support sizes of 4. If we want to support different sizes
+ // some more complicated bookkeeping should be added.
+ MOZ_ASSERT(aSize == sSupportedBlockSize);
+ MOZ_ASSERT(aShmemSection);
+
+ if (!IPCOpen()) {
+ gfxCriticalError() << "Attempt to allocate a ShmemSection after shutdown.";
+ return false;
+ }
+
+ uint32_t allocationSize = (aSize + sizeof(ShmemSectionHeapAllocation));
+
+ for (size_t i = 0; i < mUsedShmems.size(); i++) {
+ ShmemSectionHeapHeader* header = mUsedShmems[i].get<ShmemSectionHeapHeader>();
+ if ((header->mAllocatedBlocks + 1) * allocationSize + sizeof(ShmemSectionHeapHeader) < sShmemPageSize) {
+ aShmemSection->shmem() = mUsedShmems[i];
+ MOZ_ASSERT(mUsedShmems[i].IsWritable());
+ break;
+ }
+ }
+
+ if (!aShmemSection->shmem().IsWritable()) {
+ ipc::Shmem tmp;
+ if (!mShmProvider->AllocUnsafeShmem(sShmemPageSize, OptimalShmemType(), &tmp)) {
+ return false;
+ }
+
+ ShmemSectionHeapHeader* header = tmp.get<ShmemSectionHeapHeader>();
+ header->mTotalBlocks = 0;
+ header->mAllocatedBlocks = 0;
+
+ mUsedShmems.push_back(tmp);
+ aShmemSection->shmem() = tmp;
+ }
+
+ MOZ_ASSERT(aShmemSection->shmem().IsWritable());
+
+ ShmemSectionHeapHeader* header = aShmemSection->shmem().get<ShmemSectionHeapHeader>();
+ uint8_t* heap = aShmemSection->shmem().get<uint8_t>() + sizeof(ShmemSectionHeapHeader);
+
+ ShmemSectionHeapAllocation* allocHeader = nullptr;
+
+ if (header->mTotalBlocks > header->mAllocatedBlocks) {
+ // Search for the first available block.
+ for (size_t i = 0; i < header->mTotalBlocks; i++) {
+ allocHeader = reinterpret_cast<ShmemSectionHeapAllocation*>(heap);
+
+ if (allocHeader->mStatus == STATUS_FREED) {
+ break;
+ }
+ heap += allocationSize;
+ }
+ MOZ_ASSERT(allocHeader && allocHeader->mStatus == STATUS_FREED);
+ MOZ_ASSERT(allocHeader->mSize == sSupportedBlockSize);
+ } else {
+ heap += header->mTotalBlocks * allocationSize;
+
+ header->mTotalBlocks++;
+ allocHeader = reinterpret_cast<ShmemSectionHeapAllocation*>(heap);
+ allocHeader->mSize = aSize;
+ }
+
+ MOZ_ASSERT(allocHeader);
+ header->mAllocatedBlocks++;
+ allocHeader->mStatus = STATUS_ALLOCATED;
+
+ aShmemSection->size() = aSize;
+ aShmemSection->offset() = (heap + sizeof(ShmemSectionHeapAllocation)) - aShmemSection->shmem().get<uint8_t>();
+ ShrinkShmemSectionHeap();
+ return true;
+}
+
+void
+FixedSizeSmallShmemSectionAllocator::FreeShmemSection(mozilla::layers::ShmemSection& aShmemSection)
+{
+ MOZ_ASSERT(aShmemSection.size() == sSupportedBlockSize);
+ MOZ_ASSERT(aShmemSection.offset() < sShmemPageSize - sSupportedBlockSize);
+
+ if (!aShmemSection.shmem().IsWritable()) {
+ return;
+ }
+
+ ShmemSectionHeapAllocation* allocHeader =
+ reinterpret_cast<ShmemSectionHeapAllocation*>(aShmemSection.shmem().get<char>() +
+ aShmemSection.offset() -
+ sizeof(ShmemSectionHeapAllocation));
+
+ MOZ_ASSERT(allocHeader->mSize == aShmemSection.size());
+
+ DebugOnly<bool> success = allocHeader->mStatus.compareExchange(STATUS_ALLOCATED, STATUS_FREED);
+ // If this fails something really weird is going on.
+ MOZ_ASSERT(success);
+
+ ShmemSectionHeapHeader* header = aShmemSection.shmem().get<ShmemSectionHeapHeader>();
+ header->mAllocatedBlocks--;
+}
+
+void
+FixedSizeSmallShmemSectionAllocator::DeallocShmemSection(mozilla::layers::ShmemSection& aShmemSection)
+{
+ if (!IPCOpen()) {
+ gfxCriticalNote << "Attempt to dealloc a ShmemSections after shutdown.";
+ return;
+ }
+
+ FreeShmemSection(aShmemSection);
+ ShrinkShmemSectionHeap();
+}
+
+
+void
+FixedSizeSmallShmemSectionAllocator::ShrinkShmemSectionHeap()
+{
+ if (!IPCOpen()) {
+ mUsedShmems.clear();
+ return;
+ }
+
+ // The loop will terminate as we either increase i, or decrease size
+ // every time through.
+ size_t i = 0;
+ while (i < mUsedShmems.size()) {
+ ShmemSectionHeapHeader* header = mUsedShmems[i].get<ShmemSectionHeapHeader>();
+ if (header->mAllocatedBlocks == 0) {
+ mShmProvider->DeallocShmem(mUsedShmems[i]);
+ // We don't particularly care about order, move the last one in the array
+ // to this position.
+ if (i < mUsedShmems.size() - 1) {
+ mUsedShmems[i] = mUsedShmems[mUsedShmems.size() - 1];
+ }
+ mUsedShmems.pop_back();
+ } else {
+ i++;
+ }
+ }
+}
+
+int32_t
+ClientIPCAllocator::GetMaxTextureSize() const
+{
+ return gfxPrefs::MaxTextureSize();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ISurfaceAllocator.h b/gfx/layers/ipc/ISurfaceAllocator.h
new file mode 100644
index 000000000..cd38b7e8b
--- /dev/null
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 GFX_LAYERS_ISURFACEDEALLOCATOR
+#define GFX_LAYERS_ISURFACEDEALLOCATOR
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t
+#include "gfxTypes.h"
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/RefPtr.h"
+#include "nsIMemoryReporter.h" // for nsIMemoryReporter
+#include "mozilla/Atomics.h" // for Atomic
+#include "mozilla/layers/LayersMessages.h" // for ShmemSection
+#include "LayersTypes.h"
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+class IShmemAllocator;
+} // namespace ipc
+namespace gfx {
+class DataSourceSurface;
+} // namespace gfx
+
+namespace layers {
+
+class CompositableForwarder;
+class TextureForwarder;
+
+class ShmemAllocator;
+class ShmemSectionAllocator;
+class LegacySurfaceDescriptorAllocator;
+class ClientIPCAllocator;
+class HostIPCAllocator;
+class LayersIPCChannel;
+
+enum BufferCapabilities {
+ DEFAULT_BUFFER_CAPS = 0,
+ /**
+ * The allocated buffer must be efficiently mappable as a DataSourceSurface.
+ */
+ MAP_AS_IMAGE_SURFACE = 1 << 0,
+ /**
+ * The allocated buffer will be used for GL rendering only
+ */
+ USING_GL_RENDERING_ONLY = 1 << 1
+};
+
+class SurfaceDescriptor;
+
+
+mozilla::ipc::SharedMemory::SharedMemoryType OptimalShmemType();
+
+/**
+ * An interface used to create and destroy surfaces that are shared with the
+ * Compositor process (using shmem, or gralloc, or other platform specific memory)
+ *
+ * Most of the methods here correspond to methods that are implemented by IPDL
+ * actors without a common polymorphic interface.
+ * These methods should be only called in the ipdl implementor's thread, unless
+ * specified otherwise in the implementing class.
+ */
+class ISurfaceAllocator
+{
+public:
+ MOZ_DECLARE_REFCOUNTED_TYPENAME(ISurfaceAllocator)
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ISurfaceAllocator)
+
+ ISurfaceAllocator() {}
+
+ // down-casting
+
+ virtual ShmemAllocator* AsShmemAllocator() { return nullptr; }
+
+ virtual ShmemSectionAllocator* AsShmemSectionAllocator() { return nullptr; }
+
+ virtual CompositableForwarder* AsCompositableForwarder() { return nullptr; }
+
+ virtual TextureForwarder* GetTextureForwarder() { return nullptr; }
+
+ virtual ClientIPCAllocator* AsClientAllocator() { return nullptr; }
+
+ virtual HostIPCAllocator* AsHostIPCAllocator() { return nullptr; }
+
+ virtual LegacySurfaceDescriptorAllocator*
+ AsLegacySurfaceDescriptorAllocator() { return nullptr; }
+
+ // ipc info
+
+ virtual bool IPCOpen() const { return true; }
+
+ virtual bool IsSameProcess() const = 0;
+
+ virtual bool UsesImageBridge() const { return false; }
+
+protected:
+ void Finalize() {}
+
+ virtual ~ISurfaceAllocator() {}
+};
+
+/// Methods that are specific to the client/child side.
+class ClientIPCAllocator : public ISurfaceAllocator
+{
+public:
+ ClientIPCAllocator() {}
+
+ virtual ClientIPCAllocator* AsClientAllocator() override { return this; }
+
+ virtual base::ProcessId GetParentPid() const = 0;
+
+ virtual MessageLoop * GetMessageLoop() const = 0;
+
+ virtual int32_t GetMaxTextureSize() const;
+
+ virtual void CancelWaitForRecycle(uint64_t aTextureId) = 0;
+};
+
+/// Methods that are specific to the host/parent side.
+class HostIPCAllocator : public ISurfaceAllocator
+{
+public:
+ HostIPCAllocator() {}
+
+ virtual HostIPCAllocator* AsHostIPCAllocator() override { return this; }
+
+ /**
+ * Get child side's process Id.
+ */
+ virtual base::ProcessId GetChildProcessId() = 0;
+
+ virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) = 0;
+
+ virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) = 0;
+
+ virtual void SendPendingAsyncMessages();
+
+ virtual void SetAboutToSendAsyncMessages()
+ {
+ mAboutToSendAsyncMessages = true;
+ }
+
+ bool IsAboutToSendAsyncMessages()
+ {
+ return mAboutToSendAsyncMessages;
+ }
+
+protected:
+ std::vector<AsyncParentMessageData> mPendingAsyncMessage;
+ bool mAboutToSendAsyncMessages = false;
+};
+
+/// An allocator can provide shared memory.
+///
+/// The allocated shmems can be deallocated on either process, as long as they
+/// belong to the same channel.
+class ShmemAllocator
+{
+public:
+ virtual bool AllocShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) = 0;
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) = 0;
+ virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) = 0;
+};
+
+/// An allocator that can group allocations in bigger chunks of shared memory.
+///
+/// The allocated shmem sections can only be deallocated by the same allocator
+/// instance (and only in the child process).
+class ShmemSectionAllocator
+{
+public:
+ virtual bool AllocShmemSection(uint32_t aSize, ShmemSection* aShmemSection) = 0;
+
+ virtual void DeallocShmemSection(ShmemSection& aShmemSection) = 0;
+
+ virtual void MemoryPressure() {}
+};
+
+/// Some old stuff that's still around and used for screenshots.
+///
+/// New code should not need this (see TextureClient).
+class LegacySurfaceDescriptorAllocator
+{
+public:
+ virtual bool AllocSurfaceDescriptor(const gfx::IntSize& aSize,
+ gfxContentType aContent,
+ SurfaceDescriptor* aBuffer) = 0;
+
+ virtual bool AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
+ gfxContentType aContent,
+ uint32_t aCaps,
+ SurfaceDescriptor* aBuffer) = 0;
+
+ virtual void DestroySurfaceDescriptor(SurfaceDescriptor* aSurface) = 0;
+};
+
+bool
+IsSurfaceDescriptorValid(const SurfaceDescriptor& aSurface);
+
+already_AddRefed<gfx::DrawTarget>
+GetDrawTargetForDescriptor(const SurfaceDescriptor& aDescriptor, gfx::BackendType aBackend);
+
+already_AddRefed<gfx::DataSourceSurface>
+GetSurfaceForDescriptor(const SurfaceDescriptor& aDescriptor);
+
+uint8_t*
+GetAddressFromDescriptor(const SurfaceDescriptor& aDescriptor);
+
+void
+DestroySurfaceDescriptor(mozilla::ipc::IShmemAllocator* aAllocator, SurfaceDescriptor* aSurface);
+
+class GfxMemoryImageReporter final : public nsIMemoryReporter
+{
+ ~GfxMemoryImageReporter() {}
+
+public:
+ NS_DECL_ISUPPORTS
+
+ GfxMemoryImageReporter()
+ {
+#ifdef DEBUG
+ // There must be only one instance of this class, due to |sAmount|
+ // being static.
+ static bool hasRun = false;
+ MOZ_ASSERT(!hasRun);
+ hasRun = true;
+#endif
+ }
+
+ MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
+ MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
+
+ static void DidAlloc(void* aPointer)
+ {
+ sAmount += MallocSizeOfOnAlloc(aPointer);
+ }
+
+ static void WillFree(void* aPointer)
+ {
+ sAmount -= MallocSizeOfOnFree(aPointer);
+ }
+
+ NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
+ nsISupports* aData, bool aAnonymize) override
+ {
+ MOZ_COLLECT_REPORT(
+ "explicit/gfx/heap-textures", KIND_HEAP, UNITS_BYTES, sAmount,
+ "Heap memory shared between threads by texture clients and hosts.");
+
+ return NS_OK;
+ }
+
+private:
+ // Typically we use |size_t| in memory reporters, but in the past this
+ // variable has sometimes gone negative due to missing DidAlloc() calls.
+ // Therefore, we use a signed type so that any such negative values show up
+ // as negative in about:memory, rather than as enormous positive numbers.
+ static mozilla::Atomic<ptrdiff_t> sAmount;
+};
+
+/// A simple shmem section allocator that can only allocate small
+/// fixed size elements (only intended to be used to store tile
+/// copy-on-write locks for now).
+class FixedSizeSmallShmemSectionAllocator final : public ShmemSectionAllocator
+{
+public:
+ enum AllocationStatus
+ {
+ STATUS_ALLOCATED,
+ STATUS_FREED
+ };
+
+ struct ShmemSectionHeapHeader
+ {
+ Atomic<uint32_t> mTotalBlocks;
+ Atomic<uint32_t> mAllocatedBlocks;
+ };
+
+ struct ShmemSectionHeapAllocation
+ {
+ Atomic<uint32_t> mStatus;
+ uint32_t mSize;
+ };
+
+ explicit FixedSizeSmallShmemSectionAllocator(LayersIPCChannel* aShmProvider);
+
+ ~FixedSizeSmallShmemSectionAllocator();
+
+ virtual bool AllocShmemSection(uint32_t aSize, ShmemSection* aShmemSection) override;
+
+ virtual void DeallocShmemSection(ShmemSection& aShmemSection) override;
+
+ virtual void MemoryPressure() override { ShrinkShmemSectionHeap(); }
+
+ // can be called on the compositor process.
+ static void FreeShmemSection(ShmemSection& aShmemSection);
+
+ void ShrinkShmemSectionHeap();
+
+ bool IPCOpen() const;
+
+protected:
+ std::vector<mozilla::ipc::Shmem> mUsedShmems;
+ LayersIPCChannel* mShmProvider;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp
new file mode 100644
index 000000000..0466a1031
--- /dev/null
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -0,0 +1,1239 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "ImageBridgeChild.h"
+#include <vector> // for vector
+#include "ImageBridgeParent.h" // for ImageBridgeParent
+#include "ImageContainer.h" // for ImageContainer
+#include "Layers.h" // for Layer, etc
+#include "ShadowLayers.h" // for ShadowLayerForwarder
+#include "base/message_loop.h" // for MessageLoop
+#include "base/platform_thread.h" // for PlatformThread
+#include "base/process.h" // for ProcessId
+#include "base/task.h" // for NewRunnableFunction, etc
+#include "base/thread.h" // for Thread
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
+#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
+#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
+#include "mozilla/ipc/Transport.h" // for Transport
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/layers/AsyncCanvasRenderer.h"
+#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
+#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
+#include "mozilla/layers/CompositableChild.h"
+#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
+#include "mozilla/layers/ImageClient.h" // for ImageClient
+#include "mozilla/layers/ImageContainerChild.h"
+#include "mozilla/layers/LayersMessages.h" // for CompositableOperation
+#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "mtransport/runnable_utils.h"
+#include "nsContentUtils.h"
+#include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc
+#include "nsTArray.h" // for AutoTArray, nsTArray, etc
+#include "nsTArrayForwardDeclare.h" // for AutoTArray
+#include "nsThreadUtils.h" // for NS_IsMainThread
+#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h" // for StaticRefPtr
+#include "mozilla/layers/TextureClient.h"
+#include "SynchronousTask.h"
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+using base::Thread;
+using base::ProcessId;
+using namespace mozilla::ipc;
+using namespace mozilla::gfx;
+using namespace mozilla::media;
+
+typedef std::vector<CompositableOperation> OpVector;
+typedef nsTArray<OpDestroy> OpDestroyVector;
+
+namespace {
+class ImageBridgeThread : public Thread {
+public:
+
+ ImageBridgeThread() : Thread("ImageBridgeChild") {
+ }
+
+protected:
+
+ MOZ_IS_CLASS_INIT
+ void Init() {
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ mPseudoStackHack = mozilla_get_pseudo_stack();
+#endif
+ }
+
+ void CleanUp() {
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ mPseudoStackHack = nullptr;
+#endif
+ }
+
+private:
+
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ // This is needed to avoid a spurious leak report. There's no other
+ // use for it. See bug 1239504 and bug 1215265.
+ MOZ_INIT_OUTSIDE_CTOR PseudoStack* mPseudoStackHack;
+#endif
+};
+}
+
+struct CompositableTransaction
+{
+ CompositableTransaction()
+ : mSwapRequired(false)
+ , mFinished(true)
+ {}
+ ~CompositableTransaction()
+ {
+ End();
+ }
+ bool Finished() const
+ {
+ return mFinished;
+ }
+ void Begin()
+ {
+ MOZ_ASSERT(mFinished);
+ mFinished = false;
+ }
+ void End()
+ {
+ mFinished = true;
+ mSwapRequired = false;
+ mOperations.clear();
+ mDestroyedActors.Clear();
+ }
+ bool IsEmpty() const
+ {
+ return mOperations.empty() && mDestroyedActors.IsEmpty();
+ }
+ void AddNoSwapEdit(const CompositableOperation& op)
+ {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mOperations.push_back(op);
+ }
+ void AddEdit(const CompositableOperation& op)
+ {
+ AddNoSwapEdit(op);
+ MarkSyncTransaction();
+ }
+ void MarkSyncTransaction()
+ {
+ mSwapRequired = true;
+ }
+
+ OpVector mOperations;
+ OpDestroyVector mDestroyedActors;
+ bool mSwapRequired;
+ bool mFinished;
+};
+
+struct AutoEndTransaction {
+ explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
+ ~AutoEndTransaction() { mTxn->End(); }
+ CompositableTransaction* mTxn;
+};
+
+void
+ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures)
+{
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(aCompositable->GetIPDLActor());
+ MOZ_ASSERT(aCompositable->IsConnected());
+
+ AutoTArray<TimedTexture,4> textures;
+
+ for (auto& t : aTextures) {
+ MOZ_ASSERT(t.mTextureClient);
+ MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
+
+ if (!t.mTextureClient->IsSharedWithCompositor()) {
+ return;
+ }
+
+ ReadLockDescriptor readLock;
+ t.mTextureClient->SerializeReadLock(readLock);
+
+ textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
+ readLock,
+ t.mTimeStamp, t.mPictureRect,
+ t.mFrameID, t.mProducerID));
+
+ // Wait end of usage on host side if TextureFlags::RECYCLE is set or GrallocTextureData case
+ HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
+ }
+ mTxn->AddNoSwapEdit(CompositableOperation(nullptr, aCompositable->GetIPDLActor(),
+ OpUseTexture(textures)));
+}
+
+void
+ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
+ TextureClient* aTextureOnBlack,
+ TextureClient* aTextureOnWhite)
+{
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(aTextureOnWhite);
+ MOZ_ASSERT(aTextureOnBlack);
+ MOZ_ASSERT(aCompositable->IsConnected());
+ MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnBlack->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
+
+ ReadLockDescriptor readLockW;
+ ReadLockDescriptor readLockB;
+ aTextureOnBlack->SerializeReadLock(readLockB);
+ aTextureOnWhite->SerializeReadLock(readLockW);
+
+ HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
+ HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
+
+ mTxn->AddNoSwapEdit(
+ CompositableOperation(
+ nullptr,
+ aCompositable->GetIPDLActor(),
+ OpUseComponentAlphaTextures(
+ nullptr, aTextureOnBlack->GetIPDLActor(),
+ nullptr, aTextureOnWhite->GetIPDLActor(),
+ readLockB, readLockW
+ )
+ )
+ );
+}
+
+void
+ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
+{
+ // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on ImageBridge.
+ if (!aClient ||
+ !(aClient->GetFlags() & TextureFlags::RECYCLE)) {
+ return;
+ }
+ aClient->SetLastFwdTransactionId(GetFwdTransactionId());
+ mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
+}
+
+void
+ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
+{
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ if (aFwdTransactionId < client->GetLastFwdTransactionId()) {
+ // Released on host side, but client already requested newer use texture.
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+void
+ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+// Singleton
+static StaticMutex sImageBridgeSingletonLock;
+static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
+static Thread *sImageBridgeChildThread = nullptr;
+
+// dispatched function
+void
+ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask)
+{
+ AutoCompleteTask complete(aTask);
+
+ MOZ_ASSERT(InImageBridgeChildThread(),
+ "Should be in ImageBridgeChild thread.");
+
+ MediaSystemResourceManager::Shutdown();
+
+ // Force all managed protocols to shut themselves down cleanly
+ InfallibleTArray<PCompositableChild*> compositables;
+ ManagedPCompositableChild(compositables);
+ for (int i = compositables.Length() - 1; i >= 0; --i) {
+ auto compositable = CompositableClient::FromIPDLActor(compositables[i]);
+ if (compositable) {
+ compositable->Destroy();
+ }
+ }
+ InfallibleTArray<PTextureChild*> textures;
+ ManagedPTextureChild(textures);
+ for (int i = textures.Length() - 1; i >= 0; --i) {
+ RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
+ if (client) {
+ client->Destroy();
+ }
+ }
+
+ if (mCanSend) {
+ SendWillClose();
+ }
+ MarkShutDown();
+
+ // From now on, no message can be sent through the image bridge from the
+ // client side except the final Stop message.
+}
+
+// dispatched function
+void
+ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
+{
+ AutoCompleteTask complete(aTask);
+
+ MOZ_ASSERT(InImageBridgeChildThread(),
+ "Should be in ImageBridgeChild thread.");
+
+ if (!mCalledClose) {
+ Close();
+ mCalledClose = true;
+ }
+}
+
+void
+ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+ mCanSend = false;
+ mCalledClose = true;
+}
+
+void
+ImageBridgeChild::DeallocPImageBridgeChild()
+{
+ this->Release();
+}
+
+void
+ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
+ RefPtr<ImageClient>* result,
+ CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild)
+{
+ AutoCompleteTask complete(aTask);
+ *result = CreateImageClientNow(aType, aImageContainer, aContainerChild);
+}
+
+// dispatched function
+void
+ImageBridgeChild::CreateCanvasClientSync(SynchronousTask* aTask,
+ CanvasClient::CanvasClientType aType,
+ TextureFlags aFlags,
+ RefPtr<CanvasClient>* const outResult)
+{
+ AutoCompleteTask complete(aTask);
+ *outResult = CreateCanvasClientNow(aType, aFlags);
+}
+
+ImageBridgeChild::ImageBridgeChild()
+ : mCanSend(false)
+ , mCalledClose(false)
+ , mFwdTransactionId(0)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mTxn = new CompositableTransaction();
+}
+
+ImageBridgeChild::~ImageBridgeChild()
+{
+ delete mTxn;
+}
+
+void
+ImageBridgeChild::MarkShutDown()
+{
+ mTexturesWaitingRecycled.Clear();
+
+ mCanSend = false;
+}
+
+void
+ImageBridgeChild::Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer)
+{
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(InImageBridgeChildThread());
+ MOZ_ASSERT(CanSend());
+
+ uint64_t id = 0;
+
+ PImageContainerChild* imageContainerChild = nullptr;
+ if (aImageContainer)
+ imageContainerChild = aImageContainer->GetPImageContainerChild();
+
+ PCompositableChild* child =
+ SendPCompositableConstructor(aCompositable->GetTextureInfo(),
+ imageContainerChild, &id);
+ if (!child) {
+ return;
+ }
+ aCompositable->InitIPDLActor(child, id);
+}
+
+PCompositableChild*
+ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo,
+ PImageContainerChild* aChild, uint64_t* aID)
+{
+ MOZ_ASSERT(CanSend());
+ return AsyncCompositableChild::CreateActor();
+}
+
+bool
+ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
+{
+ AsyncCompositableChild::DestroyActor(aActor);
+ return true;
+}
+
+
+Thread* ImageBridgeChild::GetThread() const
+{
+ return sImageBridgeChildThread;
+}
+
+/* static */ RefPtr<ImageBridgeChild>
+ImageBridgeChild::GetSingleton()
+{
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ return sImageBridgeChildSingleton;
+}
+
+void
+ImageBridgeChild::ReleaseImageContainer(RefPtr<ImageContainerChild> aChild)
+{
+ if (!aChild) {
+ return;
+ }
+
+ if (!InImageBridgeChildThread()) {
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ReleaseImageContainer,
+ aChild);
+ GetMessageLoop()->PostTask(runnable.forget());
+ return;
+ }
+
+ aChild->SendAsyncDelete();
+}
+
+void
+ImageBridgeChild::ReleaseTextureClientNow(TextureClient* aClient)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+ RELEASE_MANUALLY(aClient);
+}
+
+/* static */ void
+ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
+{
+ if (!aClient) {
+ return;
+ }
+
+ RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
+ if (!imageBridge) {
+ // TextureClient::Release should normally happen in the ImageBridgeChild
+ // thread because it usually generate some IPDL messages.
+ // However, if we take this branch it means that the ImageBridgeChild
+ // has already shut down, along with the TextureChild, which means no
+ // message will be sent and it is safe to run this code from any thread.
+ MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
+ RELEASE_MANUALLY(aClient);
+ return;
+ }
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ imageBridge,
+ &ImageBridgeChild::ReleaseTextureClientNow,
+ aClient);
+ imageBridge->GetMessageLoop()->PostTask(runnable.forget());
+}
+
+void
+ImageBridgeChild::UpdateImageClient(RefPtr<ImageClient> aClient, RefPtr<ImageContainer> aContainer)
+{
+ if (!aClient || !aContainer) {
+ return;
+ }
+
+ if (!InImageBridgeChildThread()) {
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::UpdateImageClient,
+ aClient,
+ aContainer);
+ GetMessageLoop()->PostTask(runnable.forget());
+ return;
+ }
+
+ if (!CanSend()) {
+ return;
+ }
+
+ // If the client has become disconnected before this event was dispatched,
+ // early return now.
+ if (!aClient->IsConnected()) {
+ return;
+ }
+
+ BeginTransaction();
+ aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
+ EndTransaction();
+}
+
+void
+ImageBridgeChild::UpdateAsyncCanvasRendererSync(SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper)
+{
+ AutoCompleteTask complete(aTask);
+
+ UpdateAsyncCanvasRendererNow(aWrapper);
+}
+
+void
+ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper)
+{
+ aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
+
+ if (InImageBridgeChildThread()) {
+ UpdateAsyncCanvasRendererNow(aWrapper);
+ return;
+ }
+
+ SynchronousTask task("UpdateAsyncCanvasRenderer Lock");
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::UpdateAsyncCanvasRendererSync,
+ &task,
+ aWrapper);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+}
+
+void
+ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
+{
+ MOZ_ASSERT(aWrapper);
+
+ if (!CanSend()) {
+ return;
+ }
+
+ BeginTransaction();
+ aWrapper->GetCanvasClient()->Updated();
+ EndTransaction();
+}
+
+void
+ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
+ ImageClient* aClient,
+ ImageContainer* aContainer)
+{
+ AutoCompleteTask complete(aTask);
+
+ if (!CanSend()) {
+ return;
+ }
+
+ MOZ_ASSERT(aClient);
+ BeginTransaction();
+ if (aContainer) {
+ aContainer->ClearImagesFromImageBridge();
+ }
+ aClient->FlushAllImages();
+ EndTransaction();
+}
+
+void
+ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer)
+{
+ MOZ_ASSERT(aClient);
+ MOZ_ASSERT(!InImageBridgeChildThread());
+
+ if (InImageBridgeChildThread()) {
+ NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
+ return;
+ }
+
+ SynchronousTask task("FlushAllImages Lock");
+
+ // RefPtrs on arguments are not needed since this dispatches synchronously.
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::FlushAllImagesSync,
+ &task,
+ aClient,
+ aContainer);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+}
+
+void
+ImageBridgeChild::BeginTransaction()
+{
+ MOZ_ASSERT(CanSend());
+ MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
+ UpdateFwdTransactionId();
+ mTxn->Begin();
+}
+
+void
+ImageBridgeChild::EndTransaction()
+{
+ MOZ_ASSERT(CanSend());
+ MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
+
+ AutoEndTransaction _(mTxn);
+
+ if (mTxn->IsEmpty()) {
+ return;
+ }
+
+ AutoTArray<CompositableOperation, 10> cset;
+ cset.SetCapacity(mTxn->mOperations.size());
+ if (!mTxn->mOperations.empty()) {
+ cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
+ }
+
+ if (!IsSameProcess()) {
+ ShadowLayerForwarder::PlatformSyncBeforeUpdate();
+ }
+
+ AutoTArray<EditReply, 10> replies;
+
+ if (mTxn->mSwapRequired) {
+ if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId(), &replies)) {
+ NS_WARNING("could not send async texture transaction");
+ return;
+ }
+ } else {
+ // If we don't require a swap we can call SendUpdateNoSwap which
+ // assumes that aReplies is empty (DEBUG assertion)
+ if (!SendUpdateNoSwap(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
+ NS_WARNING("could not send async texture transaction (no swap)");
+ return;
+ }
+ }
+ for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
+ NS_RUNTIMEABORT("not reached");
+ }
+}
+
+void
+ImageBridgeChild::SendImageBridgeThreadId()
+{
+}
+
+bool
+ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ gfxPlatform::GetPlatform();
+
+ if (!sImageBridgeChildThread) {
+ sImageBridgeChildThread = new ImageBridgeThread();
+ if (!sImageBridgeChildThread->Start()) {
+ return false;
+ }
+ }
+
+ RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
+
+ RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
+ child,
+ &ImageBridgeChild::Bind,
+ Move(aEndpoint));
+ child->GetMessageLoop()->PostTask(runnable.forget());
+
+ // Assign this after so other threads can't post messages before we connect to IPDL.
+ {
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = child;
+ }
+
+ return true;
+}
+
+bool
+ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Note that at this point, ActorDestroy may not have been called yet,
+ // meaning mCanSend is still true. In this case we will try to send a
+ // synchronous WillClose message to the parent, and will certainly get a
+ // false result and a MsgDropped processing error. This is okay.
+ ShutdownSingleton();
+
+ return InitForContent(Move(aEndpoint));
+}
+
+void
+ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ if (!aEndpoint.Bind(this)) {
+ return;
+ }
+
+ // This reference is dropped in DeallocPImageBridgeChild.
+ this->AddRef();
+
+ mCanSend = true;
+ SendImageBridgeThreadId();
+}
+
+void
+ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent)
+{
+ MessageLoop *parentMsgLoop = aParent->GetMessageLoop();
+ ipc::MessageChannel *parentChannel = aParent->GetIPCChannel();
+ Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
+
+ // This reference is dropped in DeallocPImageBridgeChild.
+ this->AddRef();
+
+ mCanSend = true;
+ SendImageBridgeThreadId();
+}
+
+/* static */ void
+ImageBridgeChild::ShutDown()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ShutdownSingleton();
+
+ delete sImageBridgeChildThread;
+ sImageBridgeChildThread = nullptr;
+}
+
+/* static */ void
+ImageBridgeChild::ShutdownSingleton()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
+ child->WillShutdown();
+
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = nullptr;
+ }
+}
+
+void
+ImageBridgeChild::WillShutdown()
+{
+ {
+ SynchronousTask task("ImageBridge ShutdownStep1 lock");
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ShutdownStep1,
+ &task);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+ }
+
+ {
+ SynchronousTask task("ImageBridge ShutdownStep2 lock");
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ShutdownStep2,
+ &task);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+ }
+}
+
+void
+ImageBridgeChild::InitSameProcess()
+{
+ NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+
+ MOZ_ASSERT(!sImageBridgeChildSingleton);
+ MOZ_ASSERT(!sImageBridgeChildThread);
+
+ sImageBridgeChildThread = new ImageBridgeThread();
+ if (!sImageBridgeChildThread->IsRunning()) {
+ sImageBridgeChildThread->Start();
+ }
+
+ RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
+ RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ child,
+ &ImageBridgeChild::BindSameProcess,
+ parent);
+ child->GetMessageLoop()->PostTask(runnable.forget());
+
+ // Assign this after so other threads can't post messages before we connect to IPDL.
+ {
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = child;
+ }
+}
+
+/* static */ void
+ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sImageBridgeChildSingleton);
+ MOZ_ASSERT(!sImageBridgeChildThread);
+
+ sImageBridgeChildThread = new ImageBridgeThread();
+ if (!sImageBridgeChildThread->IsRunning()) {
+ sImageBridgeChildThread->Start();
+ }
+
+ RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
+
+ MessageLoop* loop = child->GetMessageLoop();
+ loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
+ child, &ImageBridgeChild::Bind, Move(aEndpoint)));
+
+ // Assign this after so other threads can't post messages before we connect to IPDL.
+ {
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = child;
+ }
+}
+
+bool InImageBridgeChildThread()
+{
+ return sImageBridgeChildThread &&
+ sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
+}
+
+MessageLoop * ImageBridgeChild::GetMessageLoop() const
+{
+ return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr;
+}
+
+/* static */ void
+ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier)
+{
+ if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
+ child->IdentifyTextureHost(aIdentifier);
+ }
+}
+
+RefPtr<ImageClient>
+ImageBridgeChild::CreateImageClient(CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild)
+{
+ if (InImageBridgeChildThread()) {
+ return CreateImageClientNow(aType, aImageContainer, aContainerChild);
+ }
+
+ SynchronousTask task("CreateImageClient Lock");
+
+ RefPtr<ImageClient> result = nullptr;
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::CreateImageClientSync,
+ &task,
+ &result,
+ aType,
+ aImageContainer,
+ aContainerChild);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return result;
+}
+
+RefPtr<ImageClient>
+ImageBridgeChild::CreateImageClientNow(CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+ if (!CanSend()) {
+ return nullptr;
+ }
+
+ if (aImageContainer) {
+ aContainerChild->RegisterWithIPDL();
+ if (!SendPImageContainerConstructor(aContainerChild)) {
+ return nullptr;
+ }
+ }
+
+ RefPtr<ImageClient> client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
+ MOZ_ASSERT(client, "failed to create ImageClient");
+ if (client) {
+ client->Connect(aImageContainer);
+ }
+ return client;
+}
+
+already_AddRefed<CanvasClient>
+ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType,
+ TextureFlags aFlag)
+{
+ if (InImageBridgeChildThread()) {
+ return CreateCanvasClientNow(aType, aFlag);
+ }
+
+ SynchronousTask task("CreateCanvasClient Lock");
+
+ // RefPtrs on arguments are not needed since this dispatches synchronously.
+ RefPtr<CanvasClient> result = nullptr;
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::CreateCanvasClientSync,
+ &task,
+ aType,
+ aFlag,
+ &result);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return result.forget();
+}
+
+already_AddRefed<CanvasClient>
+ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
+ TextureFlags aFlag)
+{
+ RefPtr<CanvasClient> client
+ = CanvasClient::CreateCanvasClient(aType, this, aFlag);
+ MOZ_ASSERT(client, "failed to create CanvasClient");
+ if (client) {
+ client->Connect();
+ }
+ return client.forget();
+}
+
+bool
+ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (!InImageBridgeChildThread()) {
+ return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe
+ }
+
+ if (!CanSend()) {
+ return false;
+ }
+ return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+bool
+ImageBridgeChild::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (!InImageBridgeChildThread()) {
+ return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
+ }
+
+ if (!CanSend()) {
+ return false;
+ }
+ return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
+}
+
+// NewRunnableFunction accepts a limited number of parameters so we need a
+// struct here
+struct AllocShmemParams {
+ size_t mSize;
+ ipc::SharedMemory::SharedMemoryType mType;
+ ipc::Shmem* mShmem;
+ bool mUnsafe;
+ bool mSuccess;
+};
+
+void
+ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams)
+{
+ AutoCompleteTask complete(aTask);
+
+ if (!CanSend()) {
+ return;
+ }
+
+ bool ok = false;
+ if (aParams->mUnsafe) {
+ ok = AllocUnsafeShmem(aParams->mSize, aParams->mType, aParams->mShmem);
+ } else {
+ ok = AllocShmem(aParams->mSize, aParams->mType, aParams->mShmem);
+ }
+ aParams->mSuccess = ok;
+}
+
+bool
+ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize,
+ SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem,
+ bool aUnsafe)
+{
+ SynchronousTask task("AllocatorProxy alloc");
+
+ AllocShmemParams params = {
+ aSize, aType, aShmem, aUnsafe, false
+ };
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ProxyAllocShmemNow,
+ &task,
+ &params);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return params.mSuccess;
+}
+
+void
+ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
+ ipc::Shmem* aShmem,
+ bool* aResult)
+{
+ AutoCompleteTask complete(aTask);
+
+ if (!CanSend()) {
+ return;
+ }
+ *aResult = DeallocShmem(*aShmem);
+}
+
+bool
+ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
+{
+ if (InImageBridgeChildThread()) {
+ if (!CanSend()) {
+ return false;
+ }
+ return PImageBridgeChild::DeallocShmem(aShmem);
+ }
+
+ SynchronousTask task("AllocatorProxy Dealloc");
+ bool result = false;
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ProxyDeallocShmemNow,
+ &task,
+ &aShmem,
+ &result);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+ return result;
+}
+
+PTextureChild*
+ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+ const LayersBackend&,
+ const TextureFlags&,
+ const uint64_t& aSerial)
+{
+ MOZ_ASSERT(CanSend());
+ return TextureClient::CreateIPDLActor();
+}
+
+bool
+ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
+{
+ return TextureClient::DestroyIPDLActor(actor);
+}
+
+PMediaSystemResourceManagerChild*
+ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
+{
+ MOZ_ASSERT(CanSend());
+ return new mozilla::media::MediaSystemResourceManagerChild();
+}
+
+bool
+ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
+{
+ MOZ_ASSERT(aActor);
+ delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
+ return true;
+}
+
+PImageContainerChild*
+ImageBridgeChild::AllocPImageContainerChild()
+{
+ // we always use the "power-user" ctor
+ NS_RUNTIMEABORT("not reached");
+ return nullptr;
+}
+
+bool
+ImageBridgeChild::DeallocPImageContainerChild(PImageContainerChild* actor)
+{
+ static_cast<ImageContainerChild*>(actor)->UnregisterFromIPDL();
+ return true;
+}
+
+bool
+ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
+{
+ for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
+ const AsyncParentMessageData& message = aMessages[i];
+
+ switch (message.type()) {
+ case AsyncParentMessageData::TOpNotifyNotUsed: {
+ const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
+ NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
+ break;
+ }
+ default:
+ NS_ERROR("unknown AsyncParentMessageData type");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
+{
+ for (auto& n : aNotifications) {
+ ImageContainerChild* child =
+ static_cast<ImageContainerChild*>(n.imageContainerChild());
+ if (child) {
+ child->NotifyComposite(n);
+ }
+ }
+ return true;
+}
+
+PTextureChild*
+ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial)
+{
+ MOZ_ASSERT(CanSend());
+ return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+static bool
+IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op, bool synchronously)
+{
+ if (aTxn->Finished()) {
+ return false;
+ }
+
+ aTxn->mDestroyedActors.AppendElement(op);
+
+ if (synchronously) {
+ aTxn->MarkSyncTransaction();
+ }
+
+ return true;
+}
+
+bool
+ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
+{
+ return IBCAddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
+}
+
+bool
+ImageBridgeChild::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
+{
+ return IBCAddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
+}
+
+
+void
+ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
+ TextureClient* aTexture)
+{
+ MOZ_ASSERT(CanSend());
+ MOZ_ASSERT(aTexture);
+ MOZ_ASSERT(aTexture->IsSharedWithCompositor());
+ MOZ_ASSERT(aCompositable->IsConnected());
+ if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
+ return;
+ }
+
+ CompositableOperation op(
+ nullptr, aCompositable->GetIPDLActor(),
+ OpRemoveTexture(nullptr, aTexture->GetIPDLActor()));
+
+ if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
+ mTxn->AddEdit(op);
+ } else {
+ mTxn->AddNoSwapEdit(op);
+ }
+}
+
+bool ImageBridgeChild::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void
+ImageBridgeChild::Destroy(CompositableChild* aCompositable)
+{
+ if (!InImageBridgeChildThread()) {
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::Destroy,
+ RefPtr<CompositableChild>(aCompositable));
+ GetMessageLoop()->PostTask(runnable.forget());
+ return;
+ }
+ CompositableForwarder::Destroy(aCompositable);
+}
+
+bool
+ImageBridgeChild::CanSend() const
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+ return mCanSend;
+}
+
+void
+ImageBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+{
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h
new file mode 100644
index 000000000..f068149f7
--- /dev/null
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -0,0 +1,400 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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_GFX_IMAGEBRIDGECHILD_H
+#define MOZILLA_GFX_IMAGEBRIDGECHILD_H
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/Atomics.h"
+#include "mozilla/RefPtr.h" // for already_AddRefed
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/layers/CanvasClient.h"
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/PImageBridgeChild.h"
+#include "mozilla/Mutex.h"
+#include "nsDebug.h" // for NS_RUNTIMEABORT
+#include "nsIObserver.h"
+#include "nsRegion.h" // for nsIntRegion
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
+
+class MessageLoop;
+
+namespace base {
+class Thread;
+} // namespace base
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+class AsyncCanvasRenderer;
+class ImageClient;
+class ImageContainer;
+class ImageContainerChild;
+class ImageBridgeParent;
+class CompositableClient;
+struct CompositableTransaction;
+class Image;
+class TextureClient;
+class SynchronousTask;
+struct AllocShmemParams;
+
+/**
+ * Returns true if the current thread is the ImageBrdigeChild's thread.
+ *
+ * Can be called from any thread.
+ */
+bool InImageBridgeChildThread();
+
+/**
+ * The ImageBridge protocol is meant to allow ImageContainers to forward images
+ * directly to the compositor thread/process without using the main thread.
+ *
+ * ImageBridgeChild is a CompositableForwarder just like ShadowLayerForwarder.
+ * This means it also does transactions with the compositor thread/process,
+ * except that the transactions are restricted to operations on the Compositables
+ * and cannot contain messages affecting layers directly.
+ *
+ * ImageBridgeChild is also a ISurfaceAllocator. It can be used to allocate or
+ * deallocate data that is shared with the compositor. The main differerence
+ * with other ISurfaceAllocators is that some of its overriden methods can be
+ * invoked from any thread.
+ *
+ * There are three important phases in the ImageBridge protocol. These three steps
+ * can do different things depending if (A) the ImageContainer uses ImageBridge
+ * or (B) it does not use ImageBridge:
+ *
+ * - When an ImageContainer calls its method SetCurrentImage:
+ * - (A) The image is sent directly to the compositor process through the
+ * ImageBridge IPDL protocol.
+ * On the compositor side the image is stored in a global table that associates
+ * the image with an ID corresponding to the ImageContainer, and a composition is
+ * triggered.
+ * - (B) Since it does not have an ImageBridge, the image is not sent yet.
+ * instead the will be sent to the compositor during the next layer transaction
+ * (on the main thread).
+ *
+ * - During a Layer transaction:
+ * - (A) The ImageContainer uses ImageBridge. The image is already available to the
+ * compositor process because it has been sent with SetCurrentImage. Yet, the
+ * CompositableHost on the compositor side will needs the ID referring to the
+ * ImageContainer to access the Image. So during the Swap operation that happens
+ * in the transaction, we swap the container ID rather than the image data.
+ * - (B) Since the ImageContainer does not use ImageBridge, the image data is swaped.
+ *
+ * - During composition:
+ * - (A) The CompositableHost has an AsyncID, it looks up the ID in the
+ * global table to see if there is an image. If there is no image, nothing is rendered.
+ * - (B) The CompositableHost has image data rather than an ID (meaning it is not
+ * using ImageBridge), then it just composites the image data normally.
+ *
+ * This means that there might be a possibility for the ImageBridge to send the first
+ * frame before the first layer transaction that will pass the container ID to the
+ * CompositableHost happens. In this (unlikely) case the layer is not composited
+ * until the layer transaction happens. This means this scenario is not harmful.
+ *
+ * Since sending an image through imageBridge triggers compositing, the main thread is
+ * not used at all (except for the very first transaction that provides the
+ * CompositableHost with an AsyncID).
+ */
+class ImageBridgeChild final : public PImageBridgeChild
+ , public CompositableForwarder
+ , public TextureForwarder
+{
+ friend class ImageContainer;
+
+ typedef InfallibleTArray<AsyncParentMessageData> AsyncParentMessageArray;
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageBridgeChild, override);
+
+ TextureForwarder* GetTextureForwarder() override { return this; }
+ LayersIPCActor* GetLayersIPCActor() override { return this; }
+
+ /**
+ * Creates the image bridge with a dedicated thread for ImageBridgeChild.
+ *
+ * We may want to use a specifi thread in the future. In this case, use
+ * CreateWithThread instead.
+ */
+ static void InitSameProcess();
+
+ static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint);
+ static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint);
+ static bool ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint);
+
+ /**
+ * Destroys the image bridge by calling DestroyBridge, and destroys the
+ * ImageBridge's thread.
+ *
+ * If you don't want to destroy the thread, call DestroyBridge directly
+ * instead.
+ */
+ static void ShutDown();
+
+ /**
+ * returns the singleton instance.
+ *
+ * can be called from any thread.
+ */
+ static RefPtr<ImageBridgeChild> GetSingleton();
+
+
+ static void IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier);
+
+ void BeginTransaction();
+ void EndTransaction();
+
+ /**
+ * Returns the ImageBridgeChild's thread.
+ *
+ * Can be called from any thread.
+ */
+ base::Thread * GetThread() const;
+
+ /**
+ * Returns the ImageBridgeChild's message loop.
+ *
+ * Can be called from any thread.
+ */
+ virtual MessageLoop * GetMessageLoop() const override;
+
+ virtual base::ProcessId GetParentPid() const override { return OtherPid(); }
+
+ PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo,
+ PImageContainerChild* aChild, uint64_t* aID) override;
+ bool DeallocPCompositableChild(PCompositableChild* aActor) override;
+
+ virtual PTextureChild*
+ AllocPTextureChild(const SurfaceDescriptor& aSharedData, const LayersBackend& aLayersBackend, const TextureFlags& aFlags, const uint64_t& aSerial) override;
+
+ virtual bool
+ DeallocPTextureChild(PTextureChild* actor) override;
+
+ PMediaSystemResourceManagerChild*
+ AllocPMediaSystemResourceManagerChild() override;
+ bool
+ DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor) override;
+
+ virtual PImageContainerChild*
+ AllocPImageContainerChild() override;
+ virtual bool
+ DeallocPImageContainerChild(PImageContainerChild* actor) override;
+
+ virtual bool
+ RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
+
+ virtual bool
+ RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications) override;
+
+ // Create an ImageClient from any thread.
+ RefPtr<ImageClient> CreateImageClient(
+ CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild);
+
+ // Create an ImageClient from the ImageBridge thread.
+ RefPtr<ImageClient> CreateImageClientNow(
+ CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild);
+
+ already_AddRefed<CanvasClient> CreateCanvasClient(CanvasClient::CanvasClientType aType,
+ TextureFlags aFlag);
+ void ReleaseImageContainer(RefPtr<ImageContainerChild> aChild);
+ void UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aClient);
+ void UpdateImageClient(RefPtr<ImageClient> aClient, RefPtr<ImageContainer> aContainer);
+ static void DispatchReleaseTextureClient(TextureClient* aClient);
+
+ /**
+ * Flush all Images sent to CompositableHost.
+ */
+ void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer);
+
+ virtual bool IPCOpen() const override { return mCanSend; }
+
+private:
+
+ /**
+ * This must be called by the static function DeleteImageBridgeSync defined
+ * in ImageBridgeChild.cpp ONLY.
+ */
+ ~ImageBridgeChild();
+
+ // Helpers for dispatching.
+ already_AddRefed<CanvasClient> CreateCanvasClientNow(
+ CanvasClient::CanvasClientType aType,
+ TextureFlags aFlags);
+ void CreateCanvasClientSync(
+ SynchronousTask* aTask,
+ CanvasClient::CanvasClientType aType,
+ TextureFlags aFlags,
+ RefPtr<CanvasClient>* const outResult);
+
+ void CreateImageClientSync(
+ SynchronousTask* aTask,
+ RefPtr<ImageClient>* result,
+ CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild);
+
+ void ReleaseTextureClientNow(TextureClient* aClient);
+
+ void UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aClient);
+ void UpdateAsyncCanvasRendererSync(
+ SynchronousTask* aTask,
+ AsyncCanvasRenderer* aWrapper);
+
+ void FlushAllImagesSync(
+ SynchronousTask* aTask,
+ ImageClient* aClient,
+ ImageContainer* aContainer);
+
+ void ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams);
+ void ProxyDeallocShmemNow(SynchronousTask* aTask, Shmem* aShmem, bool* aResult);
+
+public:
+ // CompositableForwarder
+
+ virtual void Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer) override;
+
+ virtual bool UsesImageBridge() const override { return true; }
+
+ /**
+ * See CompositableForwarder::UseTextures
+ */
+ virtual void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) override;
+ virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
+ TextureClient* aClientOnBlack,
+ TextureClient* aClientOnWhite) override;
+
+ void Destroy(CompositableChild* aCompositable) override;
+
+ /**
+ * Hold TextureClient ref until end of usage on host side if TextureFlags::RECYCLE is set.
+ * Host side's usage is checked via CompositableRef.
+ */
+ void HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient);
+
+ /**
+ * Notify id of Texture When host side end its use. Transaction id is used to
+ * make sure if there is no newer usage.
+ */
+ void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
+
+ virtual void CancelWaitForRecycle(uint64_t aTextureId) override;
+
+ virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
+ virtual bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override;
+
+ virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
+ TextureClient* aTexture) override;
+
+ virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
+ const SurfaceDescriptorTiles& aTileLayerDescriptor) override
+ {
+ NS_RUNTIMEABORT("should not be called");
+ }
+
+ virtual void UpdateTextureRegion(CompositableClient* aCompositable,
+ const ThebesBufferData& aThebesBufferData,
+ const nsIntRegion& aUpdatedRegion) override {
+ NS_RUNTIMEABORT("should not be called");
+ }
+
+ // ISurfaceAllocator
+
+ /**
+ * See ISurfaceAllocator.h
+ * Can be used from any thread.
+ * If used outside the ImageBridgeChild thread, it will proxy a synchronous
+ * call on the ImageBridgeChild thread.
+ */
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) override;
+ virtual bool AllocShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) override;
+
+ /**
+ * See ISurfaceAllocator.h
+ * Can be used from any thread.
+ * If used outside the ImageBridgeChild thread, it will proxy a synchronous
+ * call on the ImageBridgeChild thread.
+ */
+ virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
+ virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial) override;
+
+ virtual bool IsSameProcess() const override;
+
+ virtual void UpdateFwdTransactionId() override { ++mFwdTransactionId; }
+ virtual uint64_t GetFwdTransactionId() override { return mFwdTransactionId; }
+
+ bool InForwarderThread() override {
+ return InImageBridgeChildThread();
+ }
+
+ virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+
+protected:
+ ImageBridgeChild();
+ bool DispatchAllocShmemInternal(size_t aSize,
+ SharedMemory::SharedMemoryType aType,
+ Shmem* aShmem,
+ bool aUnsafe);
+
+ void Bind(Endpoint<PImageBridgeChild>&& aEndpoint);
+ void BindSameProcess(RefPtr<ImageBridgeParent> aParent);
+
+ void SendImageBridgeThreadId();
+
+ void WillShutdown();
+ void ShutdownStep1(SynchronousTask* aTask);
+ void ShutdownStep2(SynchronousTask* aTask);
+ void MarkShutDown();
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+ void DeallocPImageBridgeChild() override;
+
+ bool CanSend() const;
+
+ static void ShutdownSingleton();
+
+private:
+ CompositableTransaction* mTxn;
+
+ bool mCanSend;
+ bool mCalledClose;
+
+ /**
+ * Transaction id of CompositableForwarder.
+ * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction() call.
+ */
+ uint64_t mFwdTransactionId;
+
+ /**
+ * Hold TextureClients refs until end of their usages on host side.
+ * It defer calling of TextureClient recycle callback.
+ */
+ nsDataHashtable<nsUint64HashKey, RefPtr<TextureClient> > mTexturesWaitingRecycled;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp
new file mode 100644
index 000000000..7b116f520
--- /dev/null
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -0,0 +1,449 @@
+/* vim: set ts=2 sw=2 et tw=80: */
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "ImageBridgeParent.h"
+#include <stdint.h> // for uint64_t, uint32_t
+#include "CompositableHost.h" // for CompositableParent, Create
+#include "base/message_loop.h" // for MessageLoop
+#include "base/process.h" // for ProcessId
+#include "base/task.h" // for CancelableTask, DeleteTask, etc
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/Hal.h" // for hal::SetCurrentThreadPriority()
+#include "mozilla/HalTypes.h" // for hal::THREAD_PRIORITY_COMPOSITOR
+#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/Transport.h" // for Transport
+#include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
+#include "mozilla/layers/CompositableTransactionParent.h"
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/LayersMessages.h" // for EditReply
+#include "mozilla/layers/LayersSurfaces.h" // for PGrallocBufferParent
+#include "mozilla/layers/PCompositableParent.h"
+#include "mozilla/layers/PImageBridgeParent.h"
+#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
+#include "mozilla/layers/Compositor.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "mozilla/Unused.h"
+#include "nsDebug.h" // for NS_RUNTIMEABORT, etc
+#include "nsISupportsImpl.h" // for ImageBridgeParent::Release, etc
+#include "nsTArray.h" // for nsTArray, nsTArray_Impl
+#include "nsTArrayForwardDeclare.h" // for InfallibleTArray
+#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
+#include "mozilla/layers/TextureHost.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::ipc;
+using namespace mozilla::gfx;
+using namespace mozilla::media;
+
+std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
+
+StaticAutoPtr<mozilla::Monitor> sImageBridgesLock;
+
+// defined in CompositorBridgeParent.cpp
+CompositorThreadHolder* GetCompositorThreadHolder();
+
+/* static */ void
+ImageBridgeParent::Setup()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (!sImageBridgesLock) {
+ sImageBridgesLock = new Monitor("ImageBridges");
+ mozilla::ClearOnShutdown(&sImageBridgesLock);
+ }
+}
+
+ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
+ ProcessId aChildProcessId)
+ : mMessageLoop(aLoop)
+ , mSetChildThreadPriority(false)
+ , mClosed(false)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // creates the map only if it has not been created already, so it is safe
+ // with several bridges
+ CompositableMap::Create();
+ {
+ MonitorAutoLock lock(*sImageBridgesLock);
+ sImageBridges[aChildProcessId] = this;
+ }
+ SetOtherProcessId(aChildProcessId);
+}
+
+ImageBridgeParent::~ImageBridgeParent()
+{
+ nsTArray<PImageContainerParent*> parents;
+ ManagedPImageContainerParent(parents);
+ for (PImageContainerParent* p : parents) {
+ delete p;
+ }
+}
+
+static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
+
+void ReleaseImageBridgeParentSingleton() {
+ sImageBridgeParentSingleton = nullptr;
+}
+
+/* static */ ImageBridgeParent*
+ImageBridgeParent::CreateSameProcess()
+{
+ RefPtr<ImageBridgeParent> parent =
+ new ImageBridgeParent(CompositorThreadHolder::Loop(), base::GetCurrentProcId());
+ parent->mSelfRef = parent;
+
+ sImageBridgeParentSingleton = parent;
+ return parent;
+}
+
+/* static */ bool
+ImageBridgeParent::CreateForGPUProcess(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+ MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
+
+ MessageLoop* loop = CompositorThreadHolder::Loop();
+ RefPtr<ImageBridgeParent> parent = new ImageBridgeParent(loop, aEndpoint.OtherPid());
+
+ loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
+ parent, &ImageBridgeParent::Bind, Move(aEndpoint)));
+
+ sImageBridgeParentSingleton = parent;
+ return true;
+}
+
+void
+ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ // Can't alloc/dealloc shmems from now on.
+ mClosed = true;
+ {
+ MonitorAutoLock lock(*sImageBridgesLock);
+ sImageBridges.erase(OtherPid());
+ }
+ MessageLoop::current()->PostTask(NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
+
+ // It is very important that this method gets called at shutdown (be it a clean
+ // or an abnormal shutdown), because DeferredDestroy is what clears mSelfRef.
+ // If mSelfRef is not null and ActorDestroy is not called, the ImageBridgeParent
+ // is leaked which causes the CompositorThreadHolder to be leaked and
+ // CompsoitorParent's shutdown ends up spinning the event loop forever, waiting
+ // for the compositor thread to terminate.
+}
+
+bool
+ImageBridgeParent::RecvImageBridgeThreadId(const PlatformThreadId& aThreadId)
+{
+ MOZ_ASSERT(!mSetChildThreadPriority);
+ if (mSetChildThreadPriority) {
+ return false;
+ }
+ mSetChildThreadPriority = true;
+ return true;
+}
+
+class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender
+{
+public:
+ explicit AutoImageBridgeParentAsyncMessageSender(ImageBridgeParent* aImageBridge,
+ InfallibleTArray<OpDestroy>* aToDestroy = nullptr)
+ : mImageBridge(aImageBridge)
+ , mToDestroy(aToDestroy)
+ {
+ mImageBridge->SetAboutToSendAsyncMessages();
+ }
+
+ ~AutoImageBridgeParentAsyncMessageSender()
+ {
+ mImageBridge->SendPendingAsyncMessages();
+ if (mToDestroy) {
+ for (const auto& op : *mToDestroy) {
+ mImageBridge->DestroyActor(op);
+ }
+ }
+ }
+private:
+ ImageBridgeParent* mImageBridge;
+ InfallibleTArray<OpDestroy>* mToDestroy;
+};
+
+bool
+ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
+ const uint64_t& aFwdTransactionId,
+ EditReplyArray* aReply)
+{
+ // This ensures that destroy operations are always processed. It is not safe
+ // to early-return from RecvUpdate without doing so.
+ AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
+ UpdateFwdTransactionId(aFwdTransactionId);
+
+ EditReplyVector replyv;
+ for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
+ if (!ReceiveCompositableUpdate(aEdits[i], replyv)) {
+ return false;
+ }
+ }
+
+ aReply->SetCapacity(replyv.size());
+ if (replyv.size() > 0) {
+ aReply->AppendElements(&replyv.front(), replyv.size());
+ }
+
+ 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();
+ }
+
+ return true;
+}
+
+bool
+ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
+ const uint64_t& aFwdTransactionId)
+{
+ InfallibleTArray<EditReply> noReplies;
+ bool success = RecvUpdate(Move(aEdits), Move(aToDestroy), aFwdTransactionId, &noReplies);
+ MOZ_ASSERT(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits");
+ return success;
+}
+
+/* static */ bool
+ImageBridgeParent::CreateForContent(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+ MessageLoop* loop = CompositorThreadHolder::Loop();
+
+ RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aEndpoint.OtherPid());
+ loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
+ bridge, &ImageBridgeParent::Bind, Move(aEndpoint)));
+
+ return true;
+}
+
+void
+ImageBridgeParent::Bind(Endpoint<PImageBridgeParent>&& aEndpoint)
+{
+ if (!aEndpoint.Bind(this))
+ return;
+ mSelfRef = this;
+}
+
+bool ImageBridgeParent::RecvWillClose()
+{
+ // If there is any texture still alive we have to force it to deallocate the
+ // device data (GL textures, etc.) now because shortly after SenStop() returns
+ // on the child side the widget will be destroyed along with it's associated
+ // GL context.
+ InfallibleTArray<PTextureParent*> textures;
+ ManagedPTextureParent(textures);
+ for (unsigned int i = 0; i < textures.Length(); ++i) {
+ RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
+ tex->DeallocateDeviceData();
+ }
+ return true;
+}
+
+static uint64_t GenImageContainerID() {
+ static uint64_t sNextImageID = 1;
+
+ ++sNextImageID;
+ return sNextImageID;
+}
+
+PCompositableParent*
+ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo,
+ PImageContainerParent* aImageContainer,
+ uint64_t* aID)
+{
+ uint64_t id = GenImageContainerID();
+ *aID = id;
+ return CompositableHost::CreateIPDLActor(this, aInfo, id, aImageContainer);
+}
+
+bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor)
+{
+ return CompositableHost::DestroyIPDLActor(aActor);
+}
+
+PTextureParent*
+ImageBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial)
+{
+ return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+bool
+ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
+{
+ return TextureHost::DestroyIPDLActor(actor);
+}
+
+PMediaSystemResourceManagerParent*
+ImageBridgeParent::AllocPMediaSystemResourceManagerParent()
+{
+ return new mozilla::media::MediaSystemResourceManagerParent();
+}
+
+bool
+ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor)
+{
+ MOZ_ASSERT(aActor);
+ delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
+ return true;
+}
+
+PImageContainerParent*
+ImageBridgeParent::AllocPImageContainerParent()
+{
+ return new ImageContainerParent();
+}
+
+bool
+ImageBridgeParent::DeallocPImageContainerParent(PImageContainerParent* actor)
+{
+ delete actor;
+ return true;
+}
+
+void
+ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
+{
+ mozilla::Unused << SendParentAsyncMessages(aMessage);
+}
+
+class ProcessIdComparator
+{
+public:
+ bool Equals(const ImageCompositeNotification& aA,
+ const ImageCompositeNotification& aB) const
+ {
+ return aA.imageContainerParent()->OtherPid() == aB.imageContainerParent()->OtherPid();
+ }
+ bool LessThan(const ImageCompositeNotification& aA,
+ const ImageCompositeNotification& aB) const
+ {
+ return aA.imageContainerParent()->OtherPid() < aB.imageContainerParent()->OtherPid();
+ }
+};
+
+/* static */ bool
+ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications)
+{
+ // Group the notifications by destination process ID and then send the
+ // notifications in one message per group.
+ aNotifications.Sort(ProcessIdComparator());
+ uint32_t i = 0;
+ bool ok = true;
+ while (i < aNotifications.Length()) {
+ AutoTArray<ImageCompositeNotification,1> notifications;
+ notifications.AppendElement(aNotifications[i]);
+ uint32_t end = i + 1;
+ MOZ_ASSERT(aNotifications[i].imageContainerParent());
+ ProcessId pid = aNotifications[i].imageContainerParent()->OtherPid();
+ while (end < aNotifications.Length() &&
+ aNotifications[end].imageContainerParent()->OtherPid() == pid) {
+ notifications.AppendElement(aNotifications[end]);
+ ++end;
+ }
+ GetInstance(pid)->SendPendingAsyncMessages();
+ if (!GetInstance(pid)->SendDidComposite(notifications)) {
+ ok = false;
+ }
+ i = end;
+ }
+ return ok;
+}
+
+void
+ImageBridgeParent::DeferredDestroy()
+{
+ mCompositorThreadHolder = nullptr;
+ mSelfRef = nullptr; // "this" ImageBridge may get deleted here.
+}
+
+RefPtr<ImageBridgeParent>
+ImageBridgeParent::GetInstance(ProcessId aId)
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MonitorAutoLock lock(*sImageBridgesLock);
+ NS_ASSERTION(sImageBridges.count(aId) == 1, "ImageBridgeParent for the process");
+ return sImageBridges[aId];
+}
+
+void
+ImageBridgeParent::OnChannelConnected(int32_t aPid)
+{
+ mCompositorThreadHolder = GetCompositorThreadHolder();
+}
+
+
+bool
+ImageBridgeParent::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (mClosed) {
+ return false;
+ }
+ return PImageBridgeParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+ImageBridgeParent::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (mClosed) {
+ return false;
+ }
+ return PImageBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+void
+ImageBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
+{
+ if (mClosed) {
+ return;
+ }
+ PImageBridgeParent::DeallocShmem(aShmem);
+}
+
+bool ImageBridgeParent::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void
+ImageBridgeParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
+{
+ RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
+ if (!texture) {
+ return;
+ }
+
+ if (!(texture->GetFlags() & TextureFlags::RECYCLE)) {
+ return;
+ }
+
+ uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
+ mPendingAsyncMessage.push_back(
+ OpNotifyNotUsed(textureId, aTransactionId));
+
+ if (!IsAboutToSendAsyncMessages()) {
+ SendPendingAsyncMessages();
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h
new file mode 100644
index 000000000..2dc705691
--- /dev/null
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 gfx_layers_ipc_ImageBridgeParent_h_
+#define gfx_layers_ipc_ImageBridgeParent_h_
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+#include "CompositableTransactionParent.h"
+#include "ImageContainerParent.h"
+#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/PImageBridgeParent.h"
+#include "nsISupportsImpl.h"
+#include "nsTArrayForwardDeclare.h" // for InfallibleTArray
+
+class MessageLoop;
+
+namespace base {
+class Thread;
+} // namespace base
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+/**
+ * ImageBridgeParent is the manager Protocol of ImageContainerParent.
+ * It's purpose is mainly to setup the IPDL connection. Most of the
+ * interesting stuff is in ImageContainerParent.
+ */
+class ImageBridgeParent final : public PImageBridgeParent,
+ public CompositableParentManager,
+ public ShmemAllocator
+{
+public:
+ typedef InfallibleTArray<CompositableOperation> EditArray;
+ typedef InfallibleTArray<OpDestroy> OpDestroyArray;
+ typedef InfallibleTArray<EditReply> EditReplyArray;
+
+protected:
+ ImageBridgeParent(MessageLoop* aLoop, ProcessId aChildProcessId);
+
+public:
+ ~ImageBridgeParent();
+
+ /**
+ * Creates the globals of ImageBridgeParent.
+ */
+ static void Setup();
+
+ static ImageBridgeParent* CreateSameProcess();
+ static bool CreateForGPUProcess(Endpoint<PImageBridgeParent>&& aEndpoint);
+ static bool CreateForContent(Endpoint<PImageBridgeParent>&& aEndpoint);
+
+ virtual ShmemAllocator* AsShmemAllocator() override { return this; }
+
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ // CompositableParentManager
+ virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
+
+ virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
+
+ virtual base::ProcessId GetChildProcessId() override
+ {
+ return OtherPid();
+ }
+
+ // PImageBridge
+ virtual bool RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
+ virtual bool RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
+ const uint64_t& aFwdTransactionId,
+ EditReplyArray* aReply) override;
+ virtual bool RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
+ const uint64_t& aFwdTransactionId) override;
+
+ PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
+ PImageContainerParent* aImageContainer,
+ uint64_t*) override;
+ bool DeallocPCompositableParent(PCompositableParent* aActor) override;
+
+ virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial) override;
+ virtual bool DeallocPTextureParent(PTextureParent* actor) override;
+
+ PMediaSystemResourceManagerParent* AllocPMediaSystemResourceManagerParent() override;
+ bool DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor) override;
+ virtual PImageContainerParent* AllocPImageContainerParent() override;
+ virtual bool DeallocPImageContainerParent(PImageContainerParent* actor) override;
+
+ // Shutdown step 1
+ virtual bool RecvWillClose() override;
+
+ MessageLoop* GetMessageLoop() const { return mMessageLoop; }
+
+ // ShmemAllocator
+
+ virtual bool AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual void DeallocShmem(ipc::Shmem& aShmem) override;
+
+ virtual bool IsSameProcess() const override;
+
+ static RefPtr<ImageBridgeParent> GetInstance(ProcessId aId);
+
+ static bool NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications);
+
+ virtual bool UsesImageBridge() const override { return true; }
+
+ virtual bool IPCOpen() const override { return !mClosed; }
+
+protected:
+ void OnChannelConnected(int32_t pid) override;
+
+ void Bind(Endpoint<PImageBridgeParent>&& aEndpoint);
+
+private:
+ void DeferredDestroy();
+ MessageLoop* mMessageLoop;
+ // This keeps us alive until ActorDestroy(), at which point we do a
+ // deferred destruction of ourselves.
+ RefPtr<ImageBridgeParent> mSelfRef;
+
+ bool mSetChildThreadPriority;
+ bool mClosed;
+
+ /**
+ * Map of all living ImageBridgeParent instances
+ */
+ static std::map<base::ProcessId, ImageBridgeParent*> sImageBridges;
+
+ RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // gfx_layers_ipc_ImageBridgeParent_h_
diff --git a/gfx/layers/ipc/ImageContainerChild.cpp b/gfx/layers/ipc/ImageContainerChild.cpp
new file mode 100644
index 000000000..c54eb2c41
--- /dev/null
+++ b/gfx/layers/ipc/ImageContainerChild.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "ImageContainerChild.h"
+#include "ImageContainer.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/layers/ImageBridgeChild.h"
+
+namespace mozilla {
+namespace layers {
+
+ImageContainerChild::ImageContainerChild(ImageContainer* aImageContainer)
+ : mLock("ImageContainerChild")
+ , mImageContainer(aImageContainer)
+ , mIPCOpen(false)
+{
+}
+
+void
+ImageContainerChild::ForgetImageContainer()
+{
+ MutexAutoLock lock(mLock);
+ mImageContainer = nullptr;
+}
+
+void
+ImageContainerChild::NotifyComposite(const ImageCompositeNotification& aNotification)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+
+ MutexAutoLock lock(mLock);
+ if (mImageContainer) {
+ mImageContainer->NotifyCompositeInternal(aNotification);
+ }
+}
+
+void
+ImageContainerChild::RegisterWithIPDL()
+{
+ MOZ_ASSERT(!mIPCOpen);
+ MOZ_ASSERT(InImageBridgeChildThread());
+
+ AddRef();
+ mIPCOpen = true;
+}
+
+void
+ImageContainerChild::UnregisterFromIPDL()
+{
+ MOZ_ASSERT(mIPCOpen);
+ MOZ_ASSERT(InImageBridgeChildThread());
+
+ mIPCOpen = false;
+ Release();
+}
+
+void
+ImageContainerChild::SendAsyncDelete()
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+
+ if (mIPCOpen) {
+ PImageContainerChild::SendAsyncDelete();
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ImageContainerChild.h b/gfx/layers/ipc/ImageContainerChild.h
new file mode 100644
index 000000000..839540411
--- /dev/null
+++ b/gfx/layers/ipc/ImageContainerChild.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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_gfx_layers_ImageContainerChild_h
+#define mozilla_gfx_layers_ImageContainerChild_h
+
+#include "mozilla/Mutex.h"
+#include "mozilla/layers/PImageContainerChild.h"
+
+namespace mozilla {
+namespace layers {
+
+class ImageContainer;
+class ImageCompositeNotification;
+
+/**
+ * The child side of PImageContainer. It's best to avoid ImageContainer filling
+ * this role since IPDL objects should be associated with a single thread and
+ * ImageContainer definitely isn't. This object belongs to (and is always
+ * destroyed on) the ImageBridge thread, except when we need to destroy it
+ * during shutdown.
+ * An ImageContainer owns one of these; we have a weak reference to our
+ * ImageContainer.
+ */
+class ImageContainerChild final : public PImageContainerChild
+{
+public:
+ explicit ImageContainerChild(ImageContainer* aImageContainer);
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainerChild)
+
+ void RegisterWithIPDL();
+ void UnregisterFromIPDL();
+ void SendAsyncDelete();
+
+ void NotifyComposite(const ImageCompositeNotification& aNotification);
+ void ForgetImageContainer();
+
+private:
+ ~ImageContainerChild()
+ {}
+
+private:
+ Mutex mLock;
+ ImageContainer* mImageContainer;
+
+ // If mIPCOpen is false, it means the IPDL code tried to deallocate the actor
+ // before the ImageContainer released it. When this happens we don't actually
+ // delete the actor right away because the ImageContainer has a reference to
+ // it. In this case the actor will be deleted when the ImageContainer lets go
+ // of it.
+ // mIPCOpen must not be accessed off the ImageBridgeChild thread.
+ bool mIPCOpen;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_ImageContainerChild_h
diff --git a/gfx/layers/ipc/ImageContainerParent.cpp b/gfx/layers/ipc/ImageContainerParent.cpp
new file mode 100644
index 000000000..0dc0d6d32
--- /dev/null
+++ b/gfx/layers/ipc/ImageContainerParent.cpp
@@ -0,0 +1,31 @@
+/* -*- 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 "ImageContainerParent.h"
+
+#include "nsThreadUtils.h"
+#include "mozilla/layers/ImageHost.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace layers {
+
+ImageContainerParent::~ImageContainerParent()
+{
+ while (!mImageHosts.IsEmpty()) {
+ mImageHosts[mImageHosts.Length() - 1]->SetImageContainer(nullptr);
+ }
+}
+
+bool ImageContainerParent::RecvAsyncDelete()
+{
+ Unused << PImageContainerParent::Send__delete__(this);
+ return true;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ImageContainerParent.h b/gfx/layers/ipc/ImageContainerParent.h
new file mode 100644
index 000000000..849bcb44f
--- /dev/null
+++ b/gfx/layers/ipc/ImageContainerParent.h
@@ -0,0 +1,37 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_ImageContainerParent_h
+#define mozilla_layers_ImageContainerParent_h
+
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/PImageContainerParent.h"
+
+namespace mozilla {
+namespace layers {
+
+class ImageHost;
+
+class ImageContainerParent : public PImageContainerParent
+{
+public:
+ ImageContainerParent() {}
+ ~ImageContainerParent();
+
+ virtual bool RecvAsyncDelete() override;
+
+ AutoTArray<ImageHost*,1> mImageHosts;
+
+private:
+ virtual void ActorDestroy(ActorDestroyReason why) override {}
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_ImageContainerParent_h
diff --git a/gfx/layers/ipc/KnowsCompositor.h b/gfx/layers/ipc/KnowsCompositor.h
new file mode 100755
index 000000000..c4cb8092d
--- /dev/null
+++ b/gfx/layers/ipc/KnowsCompositor.h
@@ -0,0 +1,90 @@
+/* -*- 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_KNOWSCOMPOSITOR
+#define MOZILLA_LAYERS_KNOWSCOMPOSITOR
+
+#include "mozilla/layers/LayersTypes.h" // for LayersBackend
+#include "mozilla/layers/CompositorTypes.h"
+
+namespace mozilla {
+namespace layers {
+
+class SyncObject;
+class TextureForwarder;
+class LayersIPCActor;
+
+/**
+ * An abstract interface for classes that are tied to a specific Compositor across
+ * IPDL and uses TextureFactoryIdentifier to describe this Compositor.
+ */
+class KnowsCompositor {
+public:
+ NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
+ NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
+
+ KnowsCompositor();
+ ~KnowsCompositor();
+
+ void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
+
+ SyncObject* GetSyncObject() { return mSyncObject; }
+
+ int32_t GetMaxTextureSize() const
+ {
+ return mTextureFactoryIdentifier.mMaxTextureSize;
+ }
+
+ /**
+ * Returns the type of backend that is used off the main thread.
+ * We only don't allow changing the backend type at runtime so this value can
+ * be queried once and will not change until Gecko is restarted.
+ */
+ LayersBackend GetCompositorBackendType() const
+ {
+ return mTextureFactoryIdentifier.mParentBackend;
+ }
+
+ bool SupportsTextureBlitting() const
+ {
+ return mTextureFactoryIdentifier.mSupportsTextureBlitting;
+ }
+
+ bool SupportsPartialUploads() const
+ {
+ return mTextureFactoryIdentifier.mSupportsPartialUploads;
+ }
+
+ bool SupportsComponentAlpha() const
+ {
+ return mTextureFactoryIdentifier.mSupportsComponentAlpha;
+ }
+
+ const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
+ {
+ return mTextureFactoryIdentifier;
+ }
+
+ int32_t GetSerial() { return mSerial; }
+
+ /**
+ * Helpers for finding other related interface. These are infallible.
+ */
+ virtual TextureForwarder* GetTextureForwarder() = 0;
+ virtual LayersIPCActor* GetLayersIPCActor() = 0;
+
+protected:
+ TextureFactoryIdentifier mTextureFactoryIdentifier;
+ RefPtr<SyncObject> mSyncObject;
+
+ const int32_t mSerial;
+ static mozilla::Atomic<int32_t> sSerialCounter;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/LayerAnimationUtils.cpp b/gfx/layers/ipc/LayerAnimationUtils.cpp
new file mode 100644
index 000000000..60c2791ac
--- /dev/null
+++ b/gfx/layers/ipc/LayerAnimationUtils.cpp
@@ -0,0 +1,45 @@
+/* -*- 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 "LayerAnimationUtils.h"
+#include "mozilla/ComputedTimingFunction.h" // For ComputedTimingFunction
+#include "mozilla/layers/LayersMessages.h" // For TimingFunction etc.
+
+namespace mozilla {
+namespace layers {
+
+/* static */ Maybe<ComputedTimingFunction>
+AnimationUtils::TimingFunctionToComputedTimingFunction(
+ const TimingFunction& aTimingFunction)
+{
+ switch (aTimingFunction.type()) {
+ case TimingFunction::Tnull_t:
+ return Nothing();
+ case TimingFunction::TCubicBezierFunction: {
+ ComputedTimingFunction result;
+ CubicBezierFunction cbf = aTimingFunction.get_CubicBezierFunction();
+ result.Init(nsTimingFunction(cbf.x1(), cbf.y1(), cbf.x2(), cbf.y2()));
+ return Some(result);
+ }
+ case TimingFunction::TStepFunction: {
+ StepFunction sf = aTimingFunction.get_StepFunction();
+ nsTimingFunction::Type type = sf.type() == 1 ?
+ nsTimingFunction::Type::StepStart :
+ nsTimingFunction::Type::StepEnd;
+ ComputedTimingFunction result;
+ result.Init(nsTimingFunction(type, sf.steps()));
+ return Some(result);
+ }
+ default:
+ MOZ_ASSERT_UNREACHABLE(
+ "Function must be null, bezier or step");
+ break;
+ }
+ return Nothing();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerAnimationUtils.h b/gfx/layers/ipc/LayerAnimationUtils.h
new file mode 100644
index 000000000..fc807dbea
--- /dev/null
+++ b/gfx/layers/ipc/LayerAnimationUtils.h
@@ -0,0 +1,30 @@
+/* -*- 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_LayerAnimationUtils_h
+#define mozilla_layers_LayerAnimationUtils_h
+
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+
+class ComputedTimingFunction;
+
+namespace layers {
+
+class TimingFunction;
+
+class AnimationUtils
+{
+public:
+ static Maybe<ComputedTimingFunction> TimingFunctionToComputedTimingFunction(
+ const TimingFunction& aTimingFunction);
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_LayerAnimationUtils_h
diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp
new file mode 100644
index 000000000..8b60d3b51
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -0,0 +1,87 @@
+/* -*- 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 "LayerTransactionChild.h"
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/layers/CompositableChild.h"
+#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
+#include "mozilla/layers/PLayerChild.h" // for PLayerChild
+#include "mozilla/layers/PImageContainerChild.h"
+#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "nsDebug.h" // for NS_RUNTIMEABORT, 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();
+}
+
+
+PLayerChild*
+LayerTransactionChild::AllocPLayerChild()
+{
+ // we always use the "power-user" ctor
+ NS_RUNTIMEABORT("not reached");
+ return nullptr;
+}
+
+bool
+LayerTransactionChild::DeallocPLayerChild(PLayerChild* actor)
+{
+ delete actor;
+ return true;
+}
+
+PCompositableChild*
+LayerTransactionChild::AllocPCompositableChild(const TextureInfo& aInfo)
+{
+ MOZ_ASSERT(!mDestroyed);
+ return CompositableChild::CreateActor();
+}
+
+bool
+LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
+{
+ CompositableChild::DestroyActor(actor);
+ return true;
+}
+
+void
+LayerTransactionChild::ActorDestroy(ActorDestroyReason why)
+{
+ mDestroyed = true;
+#ifdef MOZ_B2G
+ // Due to poor lifetime management of gralloc (and possibly shmems) we will
+ // crash at some point in the future when we get destroyed due to abnormal
+ // shutdown. Its better just to crash here. On desktop though, we have a chance
+ // of recovering.
+ if (why == AbnormalShutdown) {
+ NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at LayerTransactionChild");
+ }
+#endif
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerTransactionChild.h b/gfx/layers/ipc/LayerTransactionChild.h
new file mode 100644
index 000000000..3d56399f4
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -0,0 +1,90 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
+#define MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
+
+#include <stdint.h> // 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 layout {
+class RenderFrameChild;
+} // namespace layout
+
+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;
+ }
+
+ uint64_t GetId() const { return mId; }
+
+protected:
+ explicit LayerTransactionChild(const uint64_t& aId)
+ : mForwarder(nullptr)
+ , mIPCOpen(false)
+ , mDestroyed(false)
+ , mId(aId)
+ {}
+ ~LayerTransactionChild() { }
+
+ virtual PLayerChild* AllocPLayerChild() override;
+ virtual bool DeallocPLayerChild(PLayerChild* actor) override;
+
+ virtual PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo) override;
+ virtual bool DeallocPCompositableChild(PCompositableChild* actor) override;
+
+ virtual 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;
+ friend class layout::RenderFrameChild;
+
+ ShadowLayerForwarder* mForwarder;
+ bool mIPCOpen;
+ bool mDestroyed;
+ uint64_t 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 000000000..c30ccee5b
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -0,0 +1,1098 @@
+/* -*- 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 "LayerTransactionParent.h"
+#include <vector> // for vector
+#include "apz/src/AsyncPanZoomController.h"
+#include "CompositableHost.h" // for CompositableParent, Get, etc
+#include "ImageLayers.h" // for ImageLayer
+#include "Layers.h" // for Layer, ContainerLayer, etc
+#include "ShadowLayerParent.h" // for ShadowLayerParent
+#include "CompositableTransactionParent.h" // for EditReplyVector
+#include "CompositorBridgeParent.h"
+#include "gfxPrefs.h"
+#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
+#include "mozilla/layers/CanvasLayerComposite.h"
+#include "mozilla/layers/ColorLayerComposite.h"
+#include "mozilla/layers/Compositor.h" // for Compositor
+#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/LayersSurfaces.h" // for PGrallocBufferParent
+#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
+#include "mozilla/layers/PCompositableParent.h"
+#include "mozilla/layers/PLayerParent.h" // for PLayerParent
+#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
+#include "mozilla/layers/PaintedLayerComposite.h"
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "mozilla/Unused.h"
+#include "nsCoord.h" // for NSAppUnitsToFloatPixels
+#include "nsDebug.h" // for NS_RUNTIMEABORT
+#include "nsDeviceContext.h" // for AppUnitsPerCSSPixel
+#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 "GeckoProfiler.h"
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/layers/AsyncCompositionManager.h"
+
+typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
+
+using mozilla::layout::RenderFrameParent;
+
+namespace mozilla {
+namespace layers {
+
+//--------------------------------------------------
+// Convenience accessors
+static ShadowLayerParent*
+cast(const PLayerParent* in)
+{
+ return const_cast<ShadowLayerParent*>(
+ static_cast<const ShadowLayerParent*>(in));
+}
+
+template<class OpCreateT>
+static ShadowLayerParent*
+AsLayerComposite(const OpCreateT& op)
+{
+ return cast(op.layerParent());
+}
+
+static ShadowLayerParent*
+AsLayerComposite(const OpSetRoot& op)
+{
+ return cast(op.rootParent());
+}
+
+static ShadowLayerParent*
+ShadowContainer(const OpInsertAfter& op)
+{
+ return cast(op.containerParent());
+}
+static ShadowLayerParent*
+ShadowChild(const OpInsertAfter& op)
+{
+ return cast(op.childLayerParent());
+}
+static ShadowLayerParent*
+ShadowAfter(const OpInsertAfter& op)
+{
+ return cast(op.afterParent());
+}
+
+static ShadowLayerParent*
+ShadowContainer(const OpPrependChild& op)
+{
+ return cast(op.containerParent());
+}
+static ShadowLayerParent*
+ShadowChild(const OpPrependChild& op)
+{
+ return cast(op.childLayerParent());
+}
+
+static ShadowLayerParent*
+ShadowContainer(const OpRemoveChild& op)
+{
+ return cast(op.containerParent());
+}
+static ShadowLayerParent*
+ShadowChild(const OpRemoveChild& op)
+{
+ return cast(op.childLayerParent());
+}
+
+static ShadowLayerParent*
+ShadowContainer(const OpRepositionChild& op)
+{
+ return cast(op.containerParent());
+}
+static ShadowLayerParent*
+ShadowChild(const OpRepositionChild& op)
+{
+ return cast(op.childLayerParent());
+}
+static ShadowLayerParent*
+ShadowAfter(const OpRepositionChild& op)
+{
+ return cast(op.afterParent());
+}
+
+static ShadowLayerParent*
+ShadowContainer(const OpRaiseToTopChild& op)
+{
+ return cast(op.containerParent());
+}
+static ShadowLayerParent*
+ShadowChild(const OpRaiseToTopChild& op)
+{
+ return cast(op.childLayerParent());
+}
+
+//--------------------------------------------------
+// LayerTransactionParent
+LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager,
+ CompositorBridgeParentBase* aBridge,
+ uint64_t aId)
+ : mLayerManager(aManager)
+ , mCompositorBridge(aBridge)
+ , mId(aId)
+ , mChildEpoch(0)
+ , mParentEpoch(0)
+ , mPendingTransaction(0)
+ , mPendingCompositorUpdates(0)
+ , mDestroyed(false)
+ , mIPCOpen(false)
+{
+}
+
+LayerTransactionParent::~LayerTransactionParent()
+{
+}
+
+void
+LayerTransactionParent::SetLayerManager(LayerManagerComposite* aLayerManager)
+{
+ mLayerManager = aLayerManager;
+ const ManagedContainer<PLayerParent>& layers = ManagedPLayerParent();
+ for (auto iter = layers.ConstIter(); !iter.Done(); iter.Next()) {
+ ShadowLayerParent* slp =
+ static_cast<ShadowLayerParent*>(iter.Get()->GetKey());
+ if (slp->AsLayer() && slp->AsLayer()->AsLayerComposite()) {
+ slp->AsLayer()->AsLayerComposite()->SetLayerManager(aLayerManager);
+ }
+ }
+}
+
+bool
+LayerTransactionParent::RecvShutdown()
+{
+ Destroy();
+ return Send__delete__(this);
+}
+
+void
+LayerTransactionParent::Destroy()
+{
+ const ManagedContainer<PLayerParent>& layers = ManagedPLayerParent();
+ for (auto iter = layers.ConstIter(); !iter.Done(); iter.Next()) {
+ ShadowLayerParent* slp =
+ static_cast<ShadowLayerParent*>(iter.Get()->GetKey());
+ slp->Destroy();
+ }
+ mDestroyed = true;
+}
+
+bool
+LayerTransactionParent::RecvUpdateNoSwap(InfallibleTArray<Edit>&& cset,
+ InfallibleTArray<OpDestroy>&& aToDestroy,
+ const uint64_t& aFwdTransactionId,
+ const uint64_t& aTransactionId,
+ const TargetConfig& targetConfig,
+ PluginsArray&& aPlugins,
+ const bool& isFirstPaint,
+ const bool& scheduleComposite,
+ const uint32_t& paintSequenceNumber,
+ const bool& isRepeatTransaction,
+ const mozilla::TimeStamp& aTransactionStart,
+ const int32_t& aPaintSyncId)
+{
+ return RecvUpdate(Move(cset), Move(aToDestroy), aFwdTransactionId,
+ aTransactionId, targetConfig, Move(aPlugins), isFirstPaint,
+ scheduleComposite, paintSequenceNumber, isRepeatTransaction,
+ aTransactionStart, aPaintSyncId, nullptr);
+}
+
+class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
+{
+public:
+ explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction,
+ InfallibleTArray<OpDestroy>* 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;
+ InfallibleTArray<OpDestroy>* mActorsToDestroy;
+};
+
+bool
+LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId,
+ const TimeDuration& aPaintTime)
+{
+ mCompositorBridge->UpdatePaintTime(this, aPaintTime);
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
+ InfallibleTArray<OpDestroy>&& aToDestroy,
+ const uint64_t& aFwdTransactionId,
+ const uint64_t& aTransactionId,
+ const TargetConfig& targetConfig,
+ PluginsArray&& aPlugins,
+ const bool& isFirstPaint,
+ const bool& scheduleComposite,
+ const uint32_t& paintSequenceNumber,
+ const bool& isRepeatTransaction,
+ const mozilla::TimeStamp& aTransactionStart,
+ const int32_t& aPaintSyncId,
+ InfallibleTArray<EditReply>* reply)
+{
+ profiler_tracing("Paint", "LayerTransaction", TRACING_INTERVAL_START);
+ PROFILER_LABEL("LayerTransactionParent", "RecvUpdate",
+ js::ProfileEntry::Category::GRAPHICS);
+
+#ifdef COMPOSITOR_PERFORMANCE_WARNING
+ TimeStamp updateStart = TimeStamp::Now();
+#endif
+
+ MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length()));
+
+ UpdateFwdTransactionId(aFwdTransactionId);
+
+ if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
+ for (const auto& op : aToDestroy) {
+ DestroyActor(op);
+ }
+ return true;
+ }
+
+ // This ensures that destroy operations are always processed. It is not safe
+ // to early-return from RecvUpdate without doing so.
+ AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
+ EditReplyVector replyv;
+
+ {
+ AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
+ layer_manager()->BeginTransaction();
+ }
+
+ // not all edits require an update to the hit testing tree
+ bool updateHitTestingTree = false;
+
+ for (EditArray::index_type i = 0; i < cset.Length(); ++i) {
+ const Edit& edit = cset[i];
+
+ switch (edit.type()) {
+ // Create* ops
+ case Edit::TOpCreatePaintedLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreatePaintedLayer"));
+
+ RefPtr<PaintedLayerComposite> layer =
+ layer_manager()->CreatePaintedLayerComposite();
+ AsLayerComposite(edit.get_OpCreatePaintedLayer())->Bind(layer);
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpCreateContainerLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateContainerLayer"));
+
+ RefPtr<ContainerLayer> layer = layer_manager()->CreateContainerLayerComposite();
+ AsLayerComposite(edit.get_OpCreateContainerLayer())->Bind(layer);
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpCreateImageLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateImageLayer"));
+
+ RefPtr<ImageLayerComposite> layer =
+ layer_manager()->CreateImageLayerComposite();
+ AsLayerComposite(edit.get_OpCreateImageLayer())->Bind(layer);
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpCreateColorLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateColorLayer"));
+
+ RefPtr<ColorLayerComposite> layer = layer_manager()->CreateColorLayerComposite();
+ AsLayerComposite(edit.get_OpCreateColorLayer())->Bind(layer);
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpCreateCanvasLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateCanvasLayer"));
+
+ RefPtr<CanvasLayerComposite> layer =
+ layer_manager()->CreateCanvasLayerComposite();
+ AsLayerComposite(edit.get_OpCreateCanvasLayer())->Bind(layer);
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpCreateRefLayer: {
+ MOZ_LAYERS_LOG(("[ParentSide] CreateRefLayer"));
+
+ RefPtr<RefLayerComposite> layer =
+ layer_manager()->CreateRefLayerComposite();
+ AsLayerComposite(edit.get_OpCreateRefLayer())->Bind(layer);
+
+ updateHitTestingTree = true;
+ break;
+ }
+
+ // Attributes
+ case Edit::TOpSetLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] SetLayerAttributes"));
+
+ const OpSetLayerAttributes& osla = edit.get_OpSetLayerAttributes();
+ ShadowLayerParent* layerParent = AsLayerComposite(osla);
+ Layer* layer = layerParent->AsLayer();
+ if (!layer) {
+ return false;
+ }
+ const LayerAttributes& attrs = osla.attrs();
+
+ const CommonLayerAttributes& common = attrs.common();
+ layer->SetLayerBounds(common.layerBounds());
+ layer->SetVisibleRegion(common.visibleRegion());
+ layer->SetEventRegions(common.eventRegions());
+ layer->SetContentFlags(common.contentFlags());
+ layer->SetOpacity(common.opacity());
+ layer->SetClipRect(common.useClipRect() ? Some(common.clipRect()) : Nothing());
+ layer->SetScrolledClip(common.scrolledClip());
+ layer->SetBaseTransform(common.transform().value());
+ layer->SetTransformIsPerspective(common.transformIsPerspective());
+ layer->SetPostScale(common.postXScale(), common.postYScale());
+ layer->SetIsFixedPosition(common.isFixedPosition());
+ if (common.isFixedPosition()) {
+ layer->SetFixedPositionData(common.fixedPositionScrollContainerId(),
+ common.fixedPositionAnchor(),
+ common.fixedPositionSides());
+ }
+ if (common.isStickyPosition()) {
+ layer->SetStickyPositionData(common.stickyScrollContainerId(),
+ common.stickyScrollRangeOuter(),
+ common.stickyScrollRangeInner());
+ }
+ layer->SetScrollbarData(common.scrollbarTargetContainerId(),
+ static_cast<Layer::ScrollDirection>(common.scrollbarDirection()),
+ common.scrollbarThumbRatio());
+ if (common.isScrollbarContainer()) {
+ layer->SetIsScrollbarContainer();
+ }
+ layer->SetMixBlendMode((gfx::CompositionOp)common.mixBlendMode());
+ layer->SetForceIsolatedGroup(common.forceIsolatedGroup());
+ if (PLayerParent* maskLayer = common.maskLayerParent()) {
+ layer->SetMaskLayer(cast(maskLayer)->AsLayer());
+ } else {
+ layer->SetMaskLayer(nullptr);
+ }
+ layer->SetAnimations(common.animations());
+ 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<RefPtr<Layer>> maskLayers;
+ for (size_t i = 0; i < common.ancestorMaskLayersParent().Length(); i++) {
+ Layer* maskLayer = cast(common.ancestorMaskLayersParent().ElementAt(i))->AsLayer();
+ 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"));
+
+ PaintedLayerComposite* paintedLayer = layerParent->AsPaintedLayerComposite();
+ if (!paintedLayer) {
+ return false;
+ }
+ const PaintedLayerAttributes& attrs =
+ specific.get_PaintedLayerAttributes();
+
+ paintedLayer->SetValidRegion(attrs.validRegion());
+
+ break;
+ }
+ case Specific::TContainerLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] container layer"));
+
+ ContainerLayerComposite* containerLayer = layerParent->AsContainerLayerComposite();
+ 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.scaleToResolution(),
+ attrs.presShellResolution());
+ containerLayer->SetEventRegionsOverride(attrs.eventRegionsOverride());
+
+ break;
+ }
+ case Specific::TColorLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] color layer"));
+
+ ColorLayerComposite* colorLayer = layerParent->AsColorLayerComposite();
+ 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"));
+
+ CanvasLayerComposite* canvasLayer = layerParent->AsCanvasLayerComposite();
+ 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"));
+
+ RefLayerComposite* refLayer = layerParent->AsRefLayerComposite();
+ if (!refLayer) {
+ return false;
+ }
+ refLayer->SetReferentId(specific.get_RefLayerAttributes().id());
+ refLayer->SetEventRegionsOverride(specific.get_RefLayerAttributes().eventRegionsOverride());
+ break;
+ }
+ case Specific::TImageLayerAttributes: {
+ MOZ_LAYERS_LOG(("[ParentSide] image layer"));
+
+ ImageLayerComposite* imageLayer = layerParent->AsImageLayerComposite();
+ if (!imageLayer) {
+ return false;
+ }
+ const ImageLayerAttributes& attrs = specific.get_ImageLayerAttributes();
+ imageLayer->SetSamplingFilter(attrs.samplingFilter());
+ imageLayer->SetScaleToSize(attrs.scaleToSize(), attrs.scaleMode());
+ break;
+ }
+ default:
+ NS_RUNTIMEABORT("not reached");
+ }
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpSetDiagnosticTypes: {
+ mLayerManager->GetCompositor()->SetDiagnosticTypes(
+ edit.get_OpSetDiagnosticTypes().diagnostics());
+ break;
+ }
+ case Edit::TOpWindowOverlayChanged: {
+ mLayerManager->SetWindowOverlayChanged();
+ break;
+ }
+ // Tree ops
+ case Edit::TOpSetRoot: {
+ MOZ_LAYERS_LOG(("[ParentSide] SetRoot"));
+
+ Layer* newRoot = AsLayerComposite(edit.get_OpSetRoot())->AsLayer();
+ if (!newRoot) {
+ return false;
+ }
+ if (newRoot->GetParent()) {
+ // newRoot is not a root!
+ return false;
+ }
+ mRoot = newRoot;
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpInsertAfter: {
+ MOZ_LAYERS_LOG(("[ParentSide] InsertAfter"));
+
+ const OpInsertAfter& oia = edit.get_OpInsertAfter();
+ Layer* child = ShadowChild(oia)->AsLayer();
+ if (!child) {
+ return false;
+ }
+ ContainerLayerComposite* container = ShadowContainer(oia)->AsContainerLayerComposite();
+ if (!container ||
+ !container->InsertAfter(child, ShadowAfter(oia)->AsLayer()))
+ {
+ return false;
+ }
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpPrependChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] PrependChild"));
+
+ const OpPrependChild& oac = edit.get_OpPrependChild();
+ Layer* child = ShadowChild(oac)->AsLayer();
+ if (!child) {
+ return false;
+ }
+ ContainerLayerComposite* container = ShadowContainer(oac)->AsContainerLayerComposite();
+ if (!container ||
+ !container->InsertAfter(child, nullptr))
+ {
+ return false;
+ }
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpRemoveChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] RemoveChild"));
+
+ const OpRemoveChild& orc = edit.get_OpRemoveChild();
+ Layer* childLayer = ShadowChild(orc)->AsLayer();
+ if (!childLayer) {
+ return false;
+ }
+ ContainerLayerComposite* container = ShadowContainer(orc)->AsContainerLayerComposite();
+ if (!container ||
+ !container->RemoveChild(childLayer))
+ {
+ return false;
+ }
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpRepositionChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] RepositionChild"));
+
+ const OpRepositionChild& orc = edit.get_OpRepositionChild();
+ Layer* child = ShadowChild(orc)->AsLayer();
+ if (!child) {
+ return false;
+ }
+ ContainerLayerComposite* container = ShadowContainer(orc)->AsContainerLayerComposite();
+ if (!container ||
+ !container->RepositionChild(child, ShadowAfter(orc)->AsLayer()))
+ {
+ return false;
+ }
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TOpRaiseToTopChild: {
+ MOZ_LAYERS_LOG(("[ParentSide] RaiseToTopChild"));
+
+ const OpRaiseToTopChild& rtc = edit.get_OpRaiseToTopChild();
+ Layer* child = ShadowChild(rtc)->AsLayer();
+ if (!child) {
+ return false;
+ }
+ ContainerLayerComposite* container = ShadowContainer(rtc)->AsContainerLayerComposite();
+ if (!container ||
+ !container->RepositionChild(child, nullptr))
+ {
+ return false;
+ }
+
+ updateHitTestingTree = true;
+ break;
+ }
+ case Edit::TCompositableOperation: {
+ if (!ReceiveCompositableUpdate(edit.get_CompositableOperation(),
+ replyv)) {
+ return false;
+ }
+ break;
+ }
+ case Edit::TOpAttachCompositable: {
+ const OpAttachCompositable& op = edit.get_OpAttachCompositable();
+ CompositableHost* host = CompositableHost::FromIPDLActor(op.compositableParent());
+ if (mPendingCompositorUpdates) {
+ // Do not attach compositables from old layer trees. Return true since
+ // content cannot handle errors.
+ return true;
+ }
+ if (!Attach(cast(op.layerParent()), host, false)) {
+ return false;
+ }
+ host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
+ break;
+ }
+ case Edit::TOpAttachAsyncCompositable: {
+ const OpAttachAsyncCompositable& op = edit.get_OpAttachAsyncCompositable();
+ PCompositableParent* compositableParent = CompositableMap::Get(op.containerID());
+ if (!compositableParent) {
+ NS_ERROR("CompositableParent not found in the map");
+ return false;
+ }
+ if (mPendingCompositorUpdates) {
+ // Do not attach compositables from old layer trees. Return true since
+ // content cannot handle errors.
+ return true;
+ }
+ CompositableHost* host = CompositableHost::FromIPDLActor(compositableParent);
+ if (!Attach(cast(op.layerParent()), host, true)) {
+ return false;
+ }
+ host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
+ break;
+ }
+ default:
+ NS_RUNTIMEABORT("not reached");
+ }
+ }
+
+ mCompositorBridge->ShadowLayersUpdated(this, aTransactionId, targetConfig,
+ aPlugins, isFirstPaint, scheduleComposite,
+ paintSequenceNumber, isRepeatTransaction,
+ aPaintSyncId, updateHitTestingTree);
+
+ {
+ AutoResolveRefLayers resolve(mCompositorBridge->GetCompositionManager(this));
+ layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
+ }
+
+ if (reply) {
+ reply->SetCapacity(replyv.size());
+ if (replyv.size() > 0) {
+ reply->AppendElements(&replyv.front(), replyv.size());
+ }
+ }
+
+ 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 = gfxPrefs::LayersDrawFPS();
+ if (drawFps) {
+ uint32_t visualWarningTrigger = gfxPrefs::LayerTransactionWarning();
+ // The default theshold is 200ms to trigger, hit red when it take 4 times longer
+ TimeDuration latency = TimeStamp::Now() - aTransactionStart;
+ if (latency > TimeDuration::FromMilliseconds(visualWarningTrigger)) {
+ float severity = (latency - TimeDuration::FromMilliseconds(visualWarningTrigger)).ToMilliseconds() /
+ (4 * visualWarningTrigger);
+ if (severity > 1.f) {
+ severity = 1.f;
+ }
+ mLayerManager->VisualFrameWarning(severity);
+ PR_LogPrint("LayerTransactionParent::RecvUpdate transaction from process %d took %f ms",
+ OtherPid(),
+ latency.ToMilliseconds());
+ }
+ }
+
+ profiler_tracing("Paint", "LayerTransaction", TRACING_INTERVAL_END);
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch)
+{
+ mChildEpoch = aLayerObserverEpoch;
+ return true;
+}
+
+bool
+LayerTransactionParent::ShouldParentObserveEpoch()
+{
+ if (mParentEpoch == mChildEpoch) {
+ return false;
+ }
+
+ mParentEpoch = mChildEpoch;
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvSetTestSampleTime(const TimeStamp& aTime)
+{
+ return mCompositorBridge->SetTestSampleTime(this, aTime);
+}
+
+bool
+LayerTransactionParent::RecvLeaveTestMode()
+{
+ mCompositorBridge->LeaveTestMode(this);
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvGetAnimationOpacity(PLayerParent* aParent,
+ float* aOpacity,
+ bool* aHasAnimationOpacity)
+{
+ *aHasAnimationOpacity = false;
+ if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
+ return false;
+ }
+
+ Layer* layer = cast(aParent)->AsLayer();
+ if (!layer) {
+ return false;
+ }
+
+ mCompositorBridge->ApplyAsyncProperties(this);
+
+ if (!layer->AsLayerComposite()->GetShadowOpacitySetByAnimation()) {
+ return true;
+ }
+
+ *aOpacity = layer->GetLocalOpacity();
+ *aHasAnimationOpacity = true;
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvGetAnimationTransform(PLayerParent* aParent,
+ MaybeTransform* aTransform)
+{
+ if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
+ return false;
+ }
+
+ Layer* layer = cast(aParent)->AsLayer();
+ if (!layer) {
+ return false;
+ }
+
+ // 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);
+
+ // This method is specific to transforms applied by animation.
+ // This is because this method uses the information stored with an animation
+ // such as the origin of the reference frame corresponding to the layer, to
+ // recover the untranslated transform from the shadow transform. For
+ // transforms that are not set by animation we don't have this information
+ // available.
+ if (!layer->AsLayerComposite()->GetShadowTransformSetByAnimation()) {
+ *aTransform = mozilla::void_t();
+ return true;
+ }
+
+ // The following code recovers the untranslated transform
+ // from the shadow transform by undoing the translations in
+ // AsyncCompositionManager::SampleValue.
+
+ Matrix4x4 transform = layer->AsLayerComposite()->GetShadowBaseTransform();
+ if (ContainerLayer* c = layer->AsContainerLayer()) {
+ // Undo the scale transform applied by AsyncCompositionManager::SampleValue
+ transform.PostScale(1.0f/c->GetInheritedXScale(),
+ 1.0f/c->GetInheritedYScale(),
+ 1.0f);
+ }
+ float scale = 1;
+ Point3D scaledOrigin;
+ Point3D transformOrigin;
+ for (uint32_t i=0; i < layer->GetAnimations().Length(); i++) {
+ if (layer->GetAnimations()[i].data().type() == AnimationData::TTransformData) {
+ const TransformData& data = layer->GetAnimations()[i].data().get_TransformData();
+ scale = data.appUnitsPerDevPixel();
+ scaledOrigin =
+ Point3D(NS_round(NSAppUnitsToFloatPixels(data.origin().x, scale)),
+ NS_round(NSAppUnitsToFloatPixels(data.origin().y, scale)),
+ 0.0f);
+ transformOrigin = data.transformOrigin();
+ break;
+ }
+ }
+
+ // 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);
+ }
+
+ // Undo the rebasing applied by
+ // nsDisplayTransform::GetResultingTransformMatrixInternal
+ transform.ChangeBasis(-transformOrigin);
+
+ // Convert to CSS pixels (this undoes the operations performed by
+ // nsStyleTransformMatrix::ProcessTranslatePart which is called from
+ // nsDisplayTransform::GetResultingTransformMatrix)
+ double devPerCss =
+ double(scale) / double(nsDeviceContext::AppUnitsPerCSSPixel());
+ transform._41 *= devPerCss;
+ transform._42 *= devPerCss;
+ transform._43 *= devPerCss;
+
+ *aTransform = transform;
+ return true;
+}
+
+static AsyncPanZoomController*
+GetAPZCForViewID(Layer* aLayer, FrameMetrics::ViewID aScrollID)
+{
+ AsyncPanZoomController* resultApzc = nullptr;
+ ForEachNode<ForwardIterator>(
+ aLayer,
+ [aScrollID, &resultApzc] (Layer* layer)
+ {
+ for (uint32_t i = 0; i < layer->GetScrollMetadataCount(); i++) {
+ if (layer->GetFrameMetrics(i).GetScrollId() == aScrollID) {
+ resultApzc = layer->GetAsyncPanZoomController(i);
+ return TraversalFlag::Abort;
+ }
+ }
+ return TraversalFlag::Continue;
+ });
+ return resultApzc;
+}
+
+bool
+LayerTransactionParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollID,
+ const float& aX, const float& aY)
+{
+ if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
+ return false;
+ }
+
+ AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
+ if (!controller) {
+ return false;
+ }
+ controller->SetTestAsyncScrollOffset(CSSPoint(aX, aY));
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollID,
+ const float& aValue)
+{
+ if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
+ return false;
+ }
+
+ AsyncPanZoomController* controller = GetAPZCForViewID(mRoot, aScrollID);
+ if (!controller) {
+ return false;
+ }
+ controller->SetTestAsyncZoom(LayerToParentLayerScale(aValue));
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvFlushApzRepaints()
+{
+ mCompositorBridge->FlushApzRepaints(this);
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData)
+{
+ mCompositorBridge->GetAPZTestData(this, aOutData);
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aValue)
+{
+ if (aProperty.Equals(NS_LITERAL_STRING("overdraw"))) {
+ *aValue = layer_manager()->GetCompositor()->GetFillRatio();
+ } else if (aProperty.Equals(NS_LITERAL_STRING("missed_hwc"))) {
+ *aValue = layer_manager()->LastFrameMissedHWC() ? 1 : 0;
+ } else {
+ *aValue = -1;
+ }
+ return true;
+}
+
+bool
+LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
+ nsTArray<ScrollableLayerGuid>&& aTargets)
+{
+ mCompositorBridge->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
+ return true;
+}
+
+bool
+LayerTransactionParent::Attach(ShadowLayerParent* aLayerParent,
+ CompositableHost* aCompositable,
+ bool aIsAsync)
+{
+ if (!aCompositable) {
+ return false;
+ }
+
+ Layer* baselayer = aLayerParent->AsLayer();
+ if (!baselayer) {
+ return false;
+ }
+ LayerComposite* layer = baselayer->AsLayerComposite();
+ if (!layer) {
+ return false;
+ }
+
+ Compositor* compositor
+ = static_cast<LayerManagerComposite*>(aLayerParent->AsLayer()->Manager())->GetCompositor();
+
+ if (!layer->SetCompositableHost(aCompositable)) {
+ // not all layer types accept a compositable, see bug 967824
+ return false;
+ }
+ aCompositable->Attach(aLayerParent->AsLayer(),
+ compositor,
+ aIsAsync
+ ? CompositableHost::ALLOW_REATTACH
+ | CompositableHost::KEEP_ATTACHED
+ : CompositableHost::NO_FLAGS);
+ return true;
+}
+
+bool
+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 true;
+}
+
+bool
+LayerTransactionParent::RecvForceComposite()
+{
+ mCompositorBridge->ForceComposite(this);
+ return true;
+}
+
+PLayerParent*
+LayerTransactionParent::AllocPLayerParent()
+{
+ return new ShadowLayerParent();
+}
+
+bool
+LayerTransactionParent::DeallocPLayerParent(PLayerParent* actor)
+{
+ delete actor;
+ return true;
+}
+
+PCompositableParent*
+LayerTransactionParent::AllocPCompositableParent(const TextureInfo& aInfo)
+{
+ return CompositableHost::CreateIPDLActor(this, aInfo, 0);
+}
+
+bool
+LayerTransactionParent::DeallocPCompositableParent(PCompositableParent* aActor)
+{
+ return CompositableHost::DestroyIPDLActor(aActor);
+}
+
+void
+LayerTransactionParent::ActorDestroy(ActorDestroyReason why)
+{
+}
+
+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);
+}
+
+void
+LayerTransactionParent::DeallocShmem(ipc::Shmem& aShmem)
+{
+ if (!mIPCOpen || mDestroyed) {
+ return;
+ }
+ PLayerTransactionParent::DeallocShmem(aShmem);
+}
+
+bool LayerTransactionParent::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void
+LayerTransactionParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& 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");
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h
new file mode 100644
index 000000000..d92aa0358
--- /dev/null
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -0,0 +1,240 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H
+#define MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // 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 "nsTArrayForwardDeclare.h" // for InfallibleTArray
+
+namespace mozilla {
+
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layout {
+class RenderFrameParent;
+} // namespace layout
+
+namespace layers {
+
+class Layer;
+class LayerManagerComposite;
+class ShadowLayerParent;
+class CompositableParent;
+class CompositorBridgeParentBase;
+
+class LayerTransactionParent final : public PLayerTransactionParent,
+ public CompositableParentManager,
+ public ShmemAllocator
+{
+ typedef mozilla::layout::RenderFrameParent RenderFrameParent;
+ typedef InfallibleTArray<Edit> EditArray;
+ typedef InfallibleTArray<OpDestroy> OpDestroyArray;
+ typedef InfallibleTArray<EditReply> EditReplyArray;
+ typedef InfallibleTArray<PluginWindowData> PluginsArray;
+
+public:
+ LayerTransactionParent(LayerManagerComposite* aManager,
+ CompositorBridgeParentBase* aBridge,
+ uint64_t aId);
+
+protected:
+ ~LayerTransactionParent();
+
+public:
+ void Destroy();
+
+ LayerManagerComposite* layer_manager() const { return mLayerManager; }
+
+ void SetLayerManager(LayerManagerComposite* aLayerManager);
+
+ uint64_t GetId() const { return mId; }
+ Layer* GetRoot() const { return mRoot; }
+
+ uint64_t GetChildEpoch() const { return mChildEpoch; }
+ bool ShouldParentObserveEpoch();
+
+ virtual ShmemAllocator* AsShmemAllocator() override { return this; }
+
+ virtual bool AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual void DeallocShmem(ipc::Shmem& aShmem) override;
+
+ virtual bool IsSameProcess() const override;
+
+ const uint64_t& GetPendingTransactionId() { return mPendingTransaction; }
+ void SetPendingTransactionId(uint64_t aId) { mPendingTransaction = aId; }
+
+ // CompositableParentManager
+ virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
+
+ virtual void SendPendingAsyncMessages() override;
+
+ virtual void SetAboutToSendAsyncMessages() override;
+
+ virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
+
+ virtual base::ProcessId GetChildProcessId() override
+ {
+ return OtherPid();
+ }
+
+ void AddPendingCompositorUpdate() {
+ mPendingCompositorUpdates++;
+ }
+ void SetPendingCompositorUpdates(uint32_t aCount) {
+ // Only called after construction.
+ MOZ_ASSERT(mPendingCompositorUpdates == 0);
+ mPendingCompositorUpdates = aCount;
+ }
+ void AcknowledgeCompositorUpdate() {
+ MOZ_ASSERT(mPendingCompositorUpdates > 0);
+ mPendingCompositorUpdates--;
+ }
+
+protected:
+ virtual bool RecvShutdown() override;
+
+ virtual bool RecvPaintTime(const uint64_t& aTransactionId,
+ const TimeDuration& aPaintTime) override;
+
+ virtual bool RecvUpdate(EditArray&& cset,
+ OpDestroyArray&& aToDestroy,
+ const uint64_t& aFwdTransactionId,
+ const uint64_t& aTransactionId,
+ const TargetConfig& targetConfig,
+ PluginsArray&& aPlugins,
+ const bool& isFirstPaint,
+ const bool& scheduleComposite,
+ const uint32_t& paintSequenceNumber,
+ const bool& isRepeatTransaction,
+ const mozilla::TimeStamp& aTransactionStart,
+ const int32_t& aPaintSyncId,
+ EditReplyArray* reply) override;
+
+ virtual bool RecvUpdateNoSwap(EditArray&& cset,
+ OpDestroyArray&& aToDestroy,
+ const uint64_t& aFwdTransactionId,
+ const uint64_t& aTransactionId,
+ const TargetConfig& targetConfig,
+ PluginsArray&& aPlugins,
+ const bool& isFirstPaint,
+ const bool& scheduleComposite,
+ const uint32_t& paintSequenceNumber,
+ const bool& isRepeatTransaction,
+ const mozilla::TimeStamp& aTransactionStart,
+ const int32_t& aPaintSyncId) override;
+
+ virtual bool RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
+
+ virtual bool RecvClearCachedResources() override;
+ virtual bool RecvForceComposite() override;
+ virtual bool RecvSetTestSampleTime(const TimeStamp& aTime) override;
+ virtual bool RecvLeaveTestMode() override;
+ virtual bool RecvGetAnimationOpacity(PLayerParent* aParent,
+ float* aOpacity,
+ bool* aHasAnimationOpacity) override;
+ virtual bool RecvGetAnimationTransform(PLayerParent* aParent,
+ MaybeTransform* aTransform)
+ override;
+ virtual bool RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aId,
+ const float& aX, const float& aY) override;
+ virtual bool RecvSetAsyncZoom(const FrameMetrics::ViewID& aId,
+ const float& aValue) override;
+ virtual bool RecvFlushApzRepaints() override;
+ virtual bool RecvGetAPZTestData(APZTestData* aOutData) override;
+ virtual bool RecvRequestProperty(const nsString& aProperty, float* aValue) override;
+ virtual bool RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
+ nsTArray<ScrollableLayerGuid>&& aTargets) override;
+
+ virtual PLayerParent* AllocPLayerParent() override;
+ virtual bool DeallocPLayerParent(PLayerParent* actor) override;
+
+ virtual PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo) override;
+ virtual bool DeallocPCompositableParent(PCompositableParent* actor) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ bool Attach(ShadowLayerParent* aLayerParent,
+ 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 CrossProcessCompositorBridgeParent;
+ friend class layout::RenderFrameParent;
+
+private:
+ RefPtr<LayerManagerComposite> mLayerManager;
+ CompositorBridgeParentBase* mCompositorBridge;
+ // Hold the root because it might be grafted under various
+ // containers in the "real" layer tree
+ RefPtr<Layer> mRoot;
+ // When this is nonzero, it refers to a layer tree owned by the
+ // compositor thread. It is always true that
+ // mId != 0 => mRoot == null
+ // because the "real tree" is owned by the compositor.
+ uint64_t 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 TabParent about
+ // (via ObserveLayerUpdate).
+ uint64_t mChildEpoch;
+ uint64_t mParentEpoch;
+
+ uint64_t mPendingTransaction;
+
+ // Number of compositor updates we're waiting for the child to
+ // acknowledge.
+ uint32_t mPendingCompositorUpdates;
+
+ // 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;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_LAYERS_LAYERTRANSACTIONPARENT_H
diff --git a/gfx/layers/ipc/LayerTreeOwnerTracker.cpp b/gfx/layers/ipc/LayerTreeOwnerTracker.cpp
new file mode 100644
index 000000000..9dac68688
--- /dev/null
+++ b/gfx/layers/ipc/LayerTreeOwnerTracker.cpp
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* 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 "LayerTreeOwnerTracker.h"
+
+#include "mozilla/StaticPtr.h" // for StaticAutoPtr
+#include "mozilla/dom/ContentParent.h" // for ContentParent
+#include "mozilla/gfx/GPUChild.h" // for GPUChild
+#include "mozilla/gfx/GPUProcessManager.h" // for GPUProcessManager
+
+#include <utility> // for std::make_pair
+
+namespace mozilla {
+namespace layers {
+
+static StaticAutoPtr<LayerTreeOwnerTracker> sSingleton;
+
+LayerTreeOwnerTracker::LayerTreeOwnerTracker() :
+ mLayerIdsLock("LayerTreeOwnerTrackerLock")
+{
+}
+
+void
+LayerTreeOwnerTracker::Initialize()
+{
+ MOZ_ASSERT(!sSingleton);
+ sSingleton = new LayerTreeOwnerTracker();
+}
+
+void
+LayerTreeOwnerTracker::Shutdown()
+{
+ sSingleton = nullptr;
+}
+
+LayerTreeOwnerTracker*
+LayerTreeOwnerTracker::Get()
+{
+ return sSingleton;
+}
+
+void
+LayerTreeOwnerTracker::Map(uint64_t aLayersId, base::ProcessId aProcessId)
+{
+ MutexAutoLock lock(mLayerIdsLock);
+
+ // Add the mapping to the list
+ mLayerIds[aLayersId] = aProcessId;
+}
+
+void
+LayerTreeOwnerTracker::Unmap(uint64_t aLayersId, base::ProcessId aProcessId)
+{
+ MutexAutoLock lock(mLayerIdsLock);
+
+ MOZ_ASSERT(mLayerIds[aLayersId] == aProcessId);
+ mLayerIds.erase(aLayersId);
+}
+
+bool
+LayerTreeOwnerTracker::IsMapped(uint64_t aLayersId, base::ProcessId aProcessId)
+{
+ MutexAutoLock lock(mLayerIdsLock);
+
+ auto iter = mLayerIds.find(aLayersId);
+ return iter != mLayerIds.end() && iter->second == aProcessId;
+}
+
+void
+LayerTreeOwnerTracker::Iterate(function<void(uint64_t aLayersId, base::ProcessId aProcessId)> aCallback)
+{
+ MutexAutoLock lock(mLayerIdsLock);
+
+ for (const auto& iter : mLayerIds) {
+ aCallback(iter.first, iter.second);
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/LayerTreeOwnerTracker.h b/gfx/layers/ipc/LayerTreeOwnerTracker.h
new file mode 100644
index 000000000..71f734bbf
--- /dev/null
+++ b/gfx/layers/ipc/LayerTreeOwnerTracker.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et 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_LayerTreeOwnerTracker_h
+#define mozilla_layers_LayerTreeOwnerTracker_h
+
+#include "base/process.h" // for base::ProcessId
+#include "mozilla/Mutex.h" // for mozilla::Mutex
+#include "mozilla/Function.h"
+
+#include <map>
+
+namespace mozilla {
+
+namespace dom {
+ class ContentParent;
+}
+
+namespace layers {
+
+/**
+ * A utility class for tracking which content processes should be allowed
+ * to access which layer trees.
+ *
+ * ProcessId's are used to track which content process can access the layer
+ * tree, and in the case of nested browser's we use the top level content
+ * processes' ProcessId.
+ *
+ * This class is only available in the main process and gpu process. Mappings
+ * are synced from main process to the gpu process. The actual syncing happens
+ * in GPUProcessManager, and so this class should not be used directly.
+ */
+class LayerTreeOwnerTracker final
+{
+public:
+ static void Initialize();
+ static void Shutdown();
+ static LayerTreeOwnerTracker* Get();
+
+ /**
+ * Map aLayersId and aProcessId together so that that process
+ * can access that layer tree.
+ */
+ void Map(uint64_t aLayersId, base::ProcessId aProcessId);
+
+ /**
+ * Remove an existing mapping.
+ */
+ void Unmap(uint64_t aLayersId, base::ProcessId aProcessId);
+
+ /**
+ * Checks whether it is okay for aProcessId to access aLayersId.
+ */
+ bool IsMapped(uint64_t aLayersId, base::ProcessId aProcessId);
+
+ void Iterate(function<void(uint64_t aLayersId, base::ProcessId aProcessId)> aCallback);
+
+private:
+ LayerTreeOwnerTracker();
+
+ mozilla::Mutex mLayerIdsLock;
+ std::map<uint64_t, base::ProcessId> mLayerIds;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_LayerTreeOwnerTracker_h
diff --git a/gfx/layers/ipc/LayersMessages.ipdlh b/gfx/layers/ipc/LayersMessages.ipdlh
new file mode 100644
index 000000000..dbbb3649a
--- /dev/null
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -0,0 +1,499 @@
+/* -*- 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 protocol PCompositable;
+include protocol PCompositorBridge;
+include protocol PLayer;
+include protocol PImageContainer;
+include protocol PRenderFrame;
+include protocol PTexture;
+
+include "gfxipc/ShadowLayerUtils.h";
+include "mozilla/GfxMessageUtils.h";
+include "ImageLayers.h";
+
+using mozilla::gfx::SamplingFilter from "mozilla/gfx/2D.h";
+using struct mozilla::gfx::Color from "mozilla/gfx/2D.h";
+using struct mozilla::gfx::Point3D from "mozilla/gfx/Point.h";
+using mozilla::gfx::IntPoint from "mozilla/gfx/Point.h";
+using class mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
+using nscoord from "nsCoord.h";
+using struct nsRect from "nsRect.h";
+using struct nsPoint from "nsPoint.h";
+using class mozilla::TimeDuration from "mozilla/TimeStamp.h";
+using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
+using mozilla::ScreenRotation from "mozilla/WidgetUtils.h";
+using nsCSSPropertyID from "nsCSSPropertyID.h";
+using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
+using mozilla::LayerMargin from "Units.h";
+using mozilla::LayerPoint from "Units.h";
+using mozilla::LayerRect from "Units.h";
+using mozilla::LayerIntRegion from "Units.h";
+using mozilla::ParentLayerIntRect from "Units.h";
+using mozilla::LayoutDeviceIntRect from "Units.h";
+using mozilla::layers::ScaleMode from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::EventRegions from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::EventRegionsOverride from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::DiagnosticTypes from "mozilla/layers/CompositorTypes.h";
+using struct mozilla::layers::ScrollMetadata from "FrameMetrics.h";
+using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
+using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::MaybeLayerClip from "FrameMetrics.h";
+
+namespace mozilla {
+namespace layers {
+
+struct TargetConfig {
+ IntRect naturalBounds;
+ ScreenRotation rotation;
+ ScreenOrientationInternal orientation;
+ nsIntRegion clearRegion;
+};
+
+// Create a shadow layer for |layer|
+struct OpCreatePaintedLayer { PLayer layer; };
+struct OpCreateContainerLayer { PLayer layer; };
+struct OpCreateImageLayer { PLayer layer; };
+struct OpCreateColorLayer { PLayer layer; };
+struct OpCreateCanvasLayer { PLayer layer; };
+struct OpCreateRefLayer { PLayer layer; };
+
+struct OpAttachCompositable {
+ PLayer layer;
+ PCompositable compositable;
+};
+
+struct OpAttachAsyncCompositable {
+ PLayer layer;
+ uint64_t containerID;
+};
+
+struct ThebesBufferData {
+ IntRect rect;
+ IntPoint rotation;
+};
+
+struct CubicBezierFunction {
+ float x1;
+ float y1;
+ float x2;
+ float y2;
+};
+
+struct StepFunction {
+ int steps;
+ // 1 = nsTimingFunction::StepStart, 2 = nsTimingFunction::StepEnd
+ int type;
+};
+
+union TimingFunction {
+ null_t;
+ CubicBezierFunction;
+ StepFunction;
+};
+
+// Send the angle with units rather than sending all angles in radians
+// to avoid having floating point error introduced by unit switching.
+struct CSSAngle {
+ float value;
+ int unit; // an nsCSSUnit that is valid for angles
+};
+
+struct LayerColor { Color value; };
+struct Perspective { float value; };
+struct RotationX { CSSAngle angle; };
+struct RotationY { CSSAngle angle; };
+struct RotationZ { CSSAngle angle; };
+struct Rotation { CSSAngle angle; };
+struct Rotation3D {
+ float x;
+ float y;
+ float z;
+ CSSAngle angle;
+};
+struct Scale {
+ float x;
+ float y;
+ float z;
+};
+struct Skew { CSSAngle x; CSSAngle y; };
+struct SkewX { CSSAngle x; };
+struct SkewY { CSSAngle y; };
+struct TransformMatrix { Matrix4x4 value; };
+struct Translation {
+ float x;
+ float y;
+ float z;
+};
+
+union TransformFunction {
+ Perspective;
+ RotationX;
+ RotationY;
+ RotationZ;
+ Rotation;
+ Rotation3D;
+ Scale;
+ Skew;
+ SkewX;
+ SkewY;
+ Translation;
+ TransformMatrix;
+};
+
+union Animatable {
+ float;
+ TransformFunction[];
+};
+
+struct AnimationSegment {
+ Animatable startState;
+ Animatable endState;
+ float startPortion;
+ float endPortion;
+ TimingFunction sampleFn;
+};
+
+// Transforms need extra information to correctly convert the list of transform
+// functions to a Matrix4x4 that can be applied directly to the layer.
+struct TransformData {
+ // the origin of the frame being transformed in app units
+ nsPoint origin;
+ // the transform-origin property for the transform in device pixels
+ Point3D transformOrigin;
+ nsRect bounds;
+ int32_t appUnitsPerDevPixel;
+};
+
+union AnimationData {
+ null_t;
+ TransformData;
+};
+
+struct Animation {
+ TimeStamp startTime;
+ TimeDuration delay;
+ // The value of the animation's current time at the moment it was created.
+ // For animations that are waiting to start, their startTime will be null.
+ // Once the animation is ready to start, we calculate an appropriate value
+ // of startTime such that we begin playback from initialCurrentTime.
+ TimeDuration initialCurrentTime;
+ TimeDuration duration;
+ // For each frame, the interpolation point is computed based on the
+ // startTime, the direction, the duration, and the current time.
+ // The segments must uniquely cover the portion from 0.0 to 1.0
+ AnimationSegment[] segments;
+ // Number of times to repeat the animation, including positive infinity.
+ // Values <= 0 mean the animation will not play (although events are still
+ // dispatched on the main thread).
+ float iterations;
+ float iterationStart;
+ // This uses the NS_STYLE_ANIMATION_DIRECTION_* constants.
+ uint8_t direction;
+ // This uses dom::FillMode.
+ uint8_t fillMode;
+ nsCSSPropertyID property;
+ AnimationData data;
+ float playbackRate;
+ // This is used in the transformed progress calculation.
+ TimingFunction easingFunction;
+ uint8_t iterationComposite;
+};
+
+// Change a layer's attributes
+struct CommonLayerAttributes {
+ IntRect layerBounds;
+ LayerIntRegion visibleRegion;
+ EventRegions eventRegions;
+ TransformMatrix transform;
+ bool transformIsPerspective;
+ float postXScale;
+ float postYScale;
+ uint32_t contentFlags;
+ float opacity;
+ bool useClipRect;
+ ParentLayerIntRect clipRect;
+ MaybeLayerClip scrolledClip;
+ bool isFixedPosition;
+ uint64_t fixedPositionScrollContainerId;
+ LayerPoint fixedPositionAnchor;
+ int32_t fixedPositionSides;
+ bool isStickyPosition;
+ uint64_t stickyScrollContainerId;
+ LayerRect stickyScrollRangeOuter;
+ LayerRect stickyScrollRangeInner;
+ uint64_t scrollbarTargetContainerId;
+ uint32_t scrollbarDirection;
+ float scrollbarThumbRatio;
+ bool isScrollbarContainer;
+ int8_t mixBlendMode;
+ bool forceIsolatedGroup;
+ nullable PLayer maskLayer;
+ PLayer[] ancestorMaskLayers;
+ // Animated colors will only honored for ColorLayers.
+ Animation[] animations;
+ nsIntRegion invalidRegion;
+ ScrollMetadata[] scrollMetadata;
+ nsCString displayListLog;
+};
+
+struct PaintedLayerAttributes {
+ nsIntRegion validRegion;
+};
+struct ContainerLayerAttributes {
+ float preXScale;
+ float preYScale;
+ float inheritedXScale;
+ float inheritedYScale;
+ float presShellResolution;
+ bool scaleToResolution;
+ EventRegionsOverride eventRegionsOverride;
+};
+struct ColorLayerAttributes { LayerColor color; IntRect bounds; };
+struct CanvasLayerAttributes { SamplingFilter samplingFilter; IntRect bounds; };
+struct RefLayerAttributes {
+ int64_t id;
+ // TODO: Once bug 1132895 is fixed we shouldn't need to propagate the override
+ // explicitly here.
+ EventRegionsOverride eventRegionsOverride;
+};
+struct ImageLayerAttributes { SamplingFilter samplingFilter; IntSize scaleToSize; ScaleMode scaleMode; };
+
+union SpecificLayerAttributes {
+ null_t;
+ PaintedLayerAttributes;
+ ContainerLayerAttributes;
+ ColorLayerAttributes;
+ CanvasLayerAttributes;
+ RefLayerAttributes;
+ ImageLayerAttributes;
+};
+
+struct LayerAttributes {
+ CommonLayerAttributes common;
+ SpecificLayerAttributes specific;
+};
+
+// See nsIWidget Configurations
+struct PluginWindowData {
+ uintptr_t windowId;
+ LayoutDeviceIntRect[] clip;
+ LayoutDeviceIntRect bounds;
+ bool visible;
+};
+
+struct OpSetLayerAttributes {
+ PLayer layer;
+ LayerAttributes attrs;
+};
+
+// Monkey with the tree structure
+struct OpSetRoot { PLayer root; };
+struct OpInsertAfter { PLayer container; PLayer childLayer; PLayer after; };
+struct OpPrependChild { PLayer container; PLayer childLayer; };
+struct OpRemoveChild { PLayer container; PLayer childLayer; };
+struct OpRepositionChild { PLayer container; PLayer childLayer; PLayer after; };
+struct OpRaiseToTopChild { PLayer container; PLayer childLayer; };
+
+struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
+struct OpWindowOverlayChanged { };
+
+struct ShmemSection {
+ Shmem shmem;
+ uint32_t offset;
+ size_t size;
+};
+
+union ReadLockDescriptor {
+ ShmemSection;
+ uintptr_t;
+ null_t;
+};
+
+union MaybeTexture {
+ PTexture;
+ null_t;
+};
+
+struct TexturedTileDescriptor {
+ PTexture texture;
+ MaybeTexture textureOnWhite;
+ IntRect updateRect;
+ ReadLockDescriptor sharedLock;
+ ReadLockDescriptor sharedLockOnWhite;
+ bool wasPlaceholder;
+};
+
+struct PlaceholderTileDescriptor {
+};
+
+union TileDescriptor {
+ TexturedTileDescriptor;
+ PlaceholderTileDescriptor;
+};
+
+struct SurfaceDescriptorTiles {
+ nsIntRegion validRegion;
+ TileDescriptor[] tiles;
+ IntPoint tileOrigin;
+ IntSize tileSize;
+ int firstTileX;
+ int firstTileY;
+ int retainedWidth;
+ int retainedHeight;
+ float resolution;
+ float frameXResolution;
+ float frameYResolution;
+ bool isProgressive;
+};
+
+struct OpUseTiledLayerBuffer {
+ SurfaceDescriptorTiles tileLayerDescriptor;
+};
+
+struct OpUseOverlaySource {
+ OverlaySource overlay;
+ IntRect picture;
+};
+
+struct OpPaintTextureRegion {
+ ThebesBufferData bufferData;
+ nsIntRegion updatedRegion;
+};
+
+/**
+ * Tells the CompositableHost to remove the corresponding TextureHost
+ */
+struct OpRemoveTexture {
+ PTexture texture;
+};
+
+struct TimedTexture {
+ PTexture texture;
+ ReadLockDescriptor sharedLock;
+ TimeStamp timeStamp;
+ IntRect picture;
+ uint32_t frameID;
+ uint32_t producerID;
+};
+
+/**
+ * Tells the compositor-side which textures to use (for example, as front buffer
+ * if there are several textures for double buffering).
+ * This provides a list of textures with timestamps, ordered by timestamp.
+ * The newest texture whose timestamp is <= the current time is rendered
+ * (where null is considered less than every other timestamp). If there is no
+ * such texture, the first texture is rendered.
+ * The first timestamp value can be null, but the others must not be.
+ * The list must not be empty.
+ */
+struct OpUseTexture {
+ TimedTexture[] textures;
+};
+
+struct OpUseComponentAlphaTextures {
+ PTexture textureOnBlack;
+ PTexture textureOnWhite;
+ ReadLockDescriptor sharedLockBlack;
+ ReadLockDescriptor sharedLockWhite;
+};
+
+union MaybeRegion {
+ nsIntRegion;
+ null_t;
+};
+
+struct OpNotifyNotUsed {
+ uint64_t TextureId;
+ uint64_t fwdTransactionId;
+};
+
+union CompositableOperationDetail {
+ OpPaintTextureRegion;
+
+ OpUseTiledLayerBuffer;
+
+ OpRemoveTexture;
+
+ OpUseTexture;
+ OpUseComponentAlphaTextures;
+ OpUseOverlaySource;
+};
+
+struct CompositableOperation {
+ PCompositable compositable;
+ CompositableOperationDetail detail;
+};
+
+// A unit of a changeset; a set of these comprise a changeset
+// If adding a new edit type that requires the hit testing tree to be updated,
+// set the updateHitTestingTree flag to true in RecvUpdate()
+union Edit {
+ OpCreatePaintedLayer;
+ OpCreateContainerLayer;
+ OpCreateImageLayer;
+ OpCreateColorLayer;
+ OpCreateCanvasLayer;
+ OpCreateRefLayer;
+
+ OpSetLayerAttributes;
+ OpSetDiagnosticTypes;
+ OpWindowOverlayChanged;
+
+ OpSetRoot;
+ OpInsertAfter;
+ OpPrependChild;
+ OpRemoveChild;
+ OpRepositionChild;
+ OpRaiseToTopChild;
+
+ OpAttachCompositable;
+ OpAttachAsyncCompositable;
+
+ CompositableOperation;
+};
+
+// Operations related to destroying resources, always handled after the other
+// operations for safety.
+union OpDestroy {
+ PTexture;
+ PCompositable;
+};
+
+// Replies to operations
+
+struct OpContentBufferSwap {
+ PCompositable compositable;
+ nsIntRegion frontUpdatedRegion;
+};
+
+/**
+ * An ImageCompositeNotification is sent the first time a particular
+ * image is composited by an ImageHost.
+ */
+struct ImageCompositeNotification {
+ PImageContainer imageContainer;
+ TimeStamp imageTimeStamp;
+ TimeStamp firstCompositeTimeStamp;
+ uint32_t frameID;
+ uint32_t producerID;
+};
+
+// Unit of a "changeset reply". This is a weird abstraction, probably
+// only to be used for buffer swapping.
+union EditReply {
+ OpContentBufferSwap;
+};
+
+union AsyncParentMessageData {
+ OpNotifyNotUsed;
+};
+
+} // namespace
+} // namespace
diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh
new file mode 100644
index 000000000..8eeda4ada
--- /dev/null
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -0,0 +1,142 @@
+/* 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/. */
+
+using struct gfxPoint from "gfxPoint.h";
+using nsIntRegion from "nsRegion.h";
+using struct mozilla::layers::SurfaceDescriptorX11 from "gfxipc/ShadowLayerUtils.h";
+using mozilla::StereoMode from "ImageTypes.h";
+using mozilla::YUVColorSpace from "ImageTypes.h";
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
+using mozilla::gfx::SurfaceFormat from "mozilla/gfx/Types.h";
+using mozilla::gfx::IntRect from "mozilla/gfx/Rect.h";
+using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
+using gfxImageFormat from "gfxTypes.h";
+using struct mozilla::layers::GonkNativeHandle from "mozilla/layers/GonkNativeHandleUtils.h";
+
+namespace mozilla {
+namespace layers {
+
+union OverlayHandle {
+ int32_t;
+ GonkNativeHandle;
+ null_t;
+};
+
+struct OverlaySource {
+ OverlayHandle handle;
+ IntSize size;
+};
+
+struct SurfaceDescriptorD3D9 {
+ // IDirect3DTexture9*
+ uintptr_t texture;
+};
+
+struct SurfaceDescriptorFileMapping {
+ WindowsHandle handle;
+ SurfaceFormat format;
+ IntSize size;
+};
+
+struct SurfaceDescriptorDIB {
+ // gfxWindowsSurface*
+ uintptr_t surface;
+};
+
+struct SurfaceDescriptorD3D10 {
+ WindowsHandle handle;
+ SurfaceFormat format;
+ IntSize size;
+};
+
+struct SurfaceDescriptorDXGIYCbCr {
+ WindowsHandle handleY;
+ WindowsHandle handleCb;
+ WindowsHandle handleCr;
+ IntSize size;
+ IntSize sizeY;
+ IntSize sizeCbCr;
+};
+
+struct SurfaceDescriptorMacIOSurface {
+ uint32_t surfaceId;
+ double scaleFactor;
+ bool isOpaque;
+};
+
+struct SurfaceTextureDescriptor {
+ uintptr_t surfTex;
+ IntSize size;
+};
+
+struct EGLImageDescriptor {
+ uintptr_t image; // `EGLImage` is a `void*`.
+ uintptr_t fence;
+ IntSize size;
+ bool hasAlpha;
+};
+
+struct SurfaceDescriptorSharedGLTexture {
+ uint32_t texture;
+ uint32_t target;
+ uintptr_t fence;
+ IntSize size;
+ bool hasAlpha;
+};
+
+struct SurfaceDescriptorGPUVideo {
+ uint64_t handle;
+};
+
+struct RGBDescriptor {
+ IntSize size;
+ SurfaceFormat format;
+ bool hasIntermediateBuffer;
+};
+
+struct YCbCrDescriptor {
+ IntSize ySize;
+ IntSize cbCrSize;
+ uint32_t yOffset;
+ uint32_t cbOffset;
+ uint32_t crOffset;
+ StereoMode stereoMode;
+ YUVColorSpace yUVColorSpace;
+ bool hasIntermediateBuffer;
+};
+
+union BufferDescriptor {
+ RGBDescriptor;
+ YCbCrDescriptor;
+};
+
+union MemoryOrShmem {
+ uintptr_t;
+ Shmem;
+};
+
+struct SurfaceDescriptorBuffer {
+ BufferDescriptor desc;
+ MemoryOrShmem data;
+};
+
+union SurfaceDescriptor {
+ SurfaceDescriptorBuffer;
+ SurfaceDescriptorD3D9;
+ SurfaceDescriptorDIB;
+ SurfaceDescriptorD3D10;
+ SurfaceDescriptorFileMapping;
+ SurfaceDescriptorDXGIYCbCr;
+ SurfaceDescriptorX11;
+ SurfaceTextureDescriptor;
+ EGLImageDescriptor;
+ SurfaceDescriptorMacIOSurface;
+ SurfaceDescriptorSharedGLTexture;
+ SurfaceDescriptorGPUVideo;
+ null_t;
+};
+
+} // namespace
+} // namespace
diff --git a/gfx/layers/ipc/PAPZ.ipdl b/gfx/layers/ipc/PAPZ.ipdl
new file mode 100644
index 000000000..e321b9ea0
--- /dev/null
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -0,0 +1,71 @@
+/* -*- 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 "mozilla/GfxMessageUtils.h";
+
+include protocol PCompositorBridge;
+
+using CSSRect from "Units.h";
+using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
+using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
+using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
+using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
+using mozilla::layers::GeckoContentController::APZStateChange from "mozilla/layers/GeckoContentController.h";
+using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
+using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
+using mozilla::layers::AsyncDragMetrics from "mozilla/layers/AsyncDragMetrics.h";
+using class nsRegion from "nsRegion.h";
+
+namespace mozilla {
+namespace layers {
+
+
+/**
+ * PAPZ is a protocol for remoting a GeckoContentController. PAPZ lives on the
+ * PCompositorBridge protocol which either connects to the compositor thread
+ * in the main process, or to the compositor thread in the gpu processs.
+ *
+ * PAPZParent lives in the compositor thread, while PAPZChild lives wherever the remoted
+ * GeckoContentController lives (generally the main thread of the main or content process).
+ * RemoteContentController implements PAPZParent, while APZChild implements PAPZChild.
+ *
+ * PAPZ is always used for ContentProcessController and only used for ChromeProcessController
+ * when there is a gpu process, otherwhise ChromeProcessController is used directly on the
+ * compositor thread. Only the methods that are used by the [Chrome,Content]ProcessController
+ * are implemented. If a new method is needed then PAPZ, APZChild, and RemoteContentController
+ * must be updated to handle it.
+ */
+sync protocol PAPZ
+{
+ manager PCompositorBridge;
+
+parent:
+
+ async __delete__();
+
+child:
+
+ async RequestContentRepaint(FrameMetrics frame);
+
+ async UpdateOverscrollVelocity(float aX, float aY, bool aIsRootContent);
+
+ async UpdateOverscrollOffset(float aX, float aY, bool aIsRootContent);
+
+ async SetScrollingRootContent(bool aIsRootContent);
+
+ async NotifyMozMouseScrollEvent(ViewID aScrollId, nsString aEvent);
+
+ async NotifyAPZStateChange(ScrollableLayerGuid aGuid, APZStateChange aChange, int aArg);
+
+ async NotifyFlushComplete();
+
+ async Destroy();
+};
+
+} // layers
+} // mozilla
diff --git a/gfx/layers/ipc/PAPZCTreeManager.ipdl b/gfx/layers/ipc/PAPZCTreeManager.ipdl
new file mode 100644
index 000000000..21d899f91
--- /dev/null
+++ b/gfx/layers/ipc/PAPZCTreeManager.ipdl
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "mozilla/GfxMessageUtils.h";
+include "ipc/nsGUIEventIPC.h";
+
+include protocol PCompositorBridge;
+
+using CSSRect from "Units.h";
+using LayoutDeviceCoord from "Units.h";
+using LayoutDeviceIntPoint from "Units.h";
+using mozilla::LayoutDevicePoint from "Units.h";
+using ScreenPoint from "Units.h";
+using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
+using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
+using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
+using mozilla::layers::AsyncDragMetrics from "mozilla/layers/AsyncDragMetrics.h";
+using mozilla::layers::GeckoContentController::TapType from "mozilla/layers/GeckoContentController.h";
+
+using nsEventStatus from "mozilla/EventForwards.h";
+using EventMessage from "mozilla/EventForwards.h";
+using mozilla::Modifiers from "mozilla/EventForwards.h";
+using class mozilla::WidgetInputEvent from "mozilla/BasicEvents.h";
+using class mozilla::WidgetMouseEventBase from "mozilla/MouseEvents.h";
+using mozilla::WidgetMouseEvent::Reason from "mozilla/MouseEvents.h";
+using class mozilla::WidgetTouchEvent from "mozilla/TouchEvents.h";
+using class mozilla::WidgetWheelEvent from "mozilla/MouseEvents.h";
+using class mozilla::InputData from "InputData.h";
+using class mozilla::MultiTouchInput from "InputData.h";
+using class mozilla::MouseInput from "InputData.h";
+using class mozilla::PanGestureInput from "InputData.h";
+using class mozilla::PinchGestureInput from "InputData.h";
+using mozilla::PinchGestureInput::PinchGestureType from "InputData.h";
+using class mozilla::TapGestureInput from "InputData.h";
+using class mozilla::ScrollWheelInput from "InputData.h";
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * PAPZCTreeManager is a protocol for remoting an IAPZCTreeManager. PAPZCTreeManager
+ * lives on the PCompositorBridge protocol which either connects to the compositor
+ * thread in the main process, or to the compositor thread in the gpu processs.
+ *
+ * PAPZCTreeManagerParent lives in the compositor thread, while PAPZCTreeManagerChild
+ * lives in the main thread of the main or the content process. APZCTreeManagerParent
+ * and APZCTreeManagerChild implement this protocol.
+ */
+sync protocol PAPZCTreeManager
+{
+manager PCompositorBridge;
+
+parent:
+
+ // These messages correspond to the methods
+ // on the IAPZCTreeManager interface
+
+ async ZoomToRect(ScrollableLayerGuid aGuid, CSSRect aRect, uint32_t Flags);
+
+ async ContentReceivedInputBlock(uint64_t aInputBlockId, bool PreventDefault);
+
+ async SetTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] Targets);
+
+ async UpdateZoomConstraints(ScrollableLayerGuid aGuid, MaybeZoomConstraints aConstraints);
+
+ async CancelAnimation(ScrollableLayerGuid aGuid);
+
+ async AdjustScrollForSurfaceShift(ScreenPoint aShift);
+
+ async SetDPI(float aDpiValue);
+
+ async SetAllowedTouchBehavior(uint64_t aInputBlockId, TouchBehaviorFlags[] aValues);
+
+ async StartScrollbarDrag(ScrollableLayerGuid aGuid, AsyncDragMetrics aDragMetrics);
+
+ async SetLongTapEnabled(bool aTapGestureEnabled);
+
+ async ProcessTouchVelocity(uint32_t aTimestampMs, float aSpeedY);
+
+ // The following messages are used to
+ // implement the ReceiveInputEvent methods
+
+ sync ReceiveMultiTouchInputEvent(MultiTouchInput aEvent)
+ returns (nsEventStatus aOutStatus,
+ MultiTouchInput aOutEvent,
+ ScrollableLayerGuid aOutTargetGuid,
+ uint64_t aOutInputBlockId);
+
+ sync ReceiveMouseInputEvent(MouseInput aEvent)
+ returns (nsEventStatus aOutStatus,
+ MouseInput aOutEvent,
+ ScrollableLayerGuid aOutTargetGuid,
+ uint64_t aOutInputBlockId);
+
+ sync ReceivePanGestureInputEvent(PanGestureInput aEvent)
+ returns (nsEventStatus aOutStatus,
+ PanGestureInput aOutEvent,
+ ScrollableLayerGuid aOutTargetGuid,
+ uint64_t aOutInputBlockId);
+
+ sync ReceivePinchGestureInputEvent(PinchGestureInput aEvent)
+ returns (nsEventStatus aOutStatus,
+ PinchGestureInput aOutEvent,
+ ScrollableLayerGuid aOutTargetGuid,
+ uint64_t aOutInputBlockId);
+
+ sync ReceiveTapGestureInputEvent(TapGestureInput aEvent)
+ returns (nsEventStatus aOutStatus,
+ TapGestureInput aOutEvent,
+ ScrollableLayerGuid aOutTargetGuid,
+ uint64_t aOutInputBlockId);
+
+ sync ReceiveScrollWheelInputEvent(ScrollWheelInput aEvent)
+ returns (nsEventStatus aOutStatus,
+ ScrollWheelInput aOutEvent,
+ ScrollableLayerGuid aOutTargetGuid,
+ uint64_t aOutInputBlockId);
+
+ async UpdateWheelTransaction(LayoutDeviceIntPoint aRefPoint, EventMessage aEventMessage);
+
+ sync TransformEventRefPoint(LayoutDeviceIntPoint aRefPoint)
+ returns (LayoutDeviceIntPoint aOutRefPoint,
+ ScrollableLayerGuid aOutTargetGuid);
+
+ async __delete__();
+
+child:
+
+ async HandleTap(TapType aType, LayoutDevicePoint point, Modifiers aModifiers,
+ ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
+
+ async NotifyPinchGesture(PinchGestureType aType, ScrollableLayerGuid aGuid,
+ LayoutDeviceCoord aSpanChange, Modifiers aModifiers);
+};
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/layers/ipc/PCompositable.ipdl b/gfx/layers/ipc/PCompositable.ipdl
new file mode 100644
index 000000000..d7754cd95
--- /dev/null
+++ b/gfx/layers/ipc/PCompositable.ipdl
@@ -0,0 +1,28 @@
+/* -*- 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 protocol PLayerTransaction;
+include protocol PImageBridge;
+include protocol PCompositorBridge;
+
+namespace mozilla {
+namespace layers {
+
+async protocol PCompositable
+{
+ manager PImageBridge or PLayerTransaction;
+child:
+ async __delete__();
+parent:
+ /**
+ * Asynchronously tell the compositor side to remove the texture.
+ */
+ async Destroy();
+};
+
+} // namespace
+} // namespace
diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl
new file mode 100644
index 000000000..03a353506
--- /dev/null
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -0,0 +1,237 @@
+/* -*- 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 PlatformWidgetTypes;
+include protocol PAPZ;
+include protocol PAPZCTreeManager;
+include protocol PBrowser;
+include protocol PCompositable;
+include protocol PCompositorWidget;
+include protocol PImageContainer;
+include protocol PLayer;
+include protocol PLayerTransaction;
+include protocol PTexture;
+include "mozilla/GfxMessageUtils.h";
+
+using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
+using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
+using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
+using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
+using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
+using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
+using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
+using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
+using mozilla::CSSIntRegion from "Units.h";
+using mozilla::LayoutDeviceIntPoint from "Units.h";
+using mozilla::LayoutDeviceIntRegion from "Units.h";
+using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
+using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
+using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
+
+namespace mozilla {
+namespace layers {
+
+
+/**
+ * The PCompositorBridge protocol is used to manage communication between
+ * the main thread and the compositor thread context. It's primary
+ * purpose is to manage the PLayerTransaction sub protocol.
+ */
+sync protocol PCompositorBridge
+{
+ manages PAPZ;
+ manages PAPZCTreeManager;
+ // A Compositor manages a single Layer Manager (PLayerTransaction)
+ manages PLayerTransaction;
+ manages PTexture;
+ manages PCompositorWidget;
+
+child:
+ // The child should invalidate retained layers. This is used for local
+ // compositor device resets, such as in CompositorD3D9, and ensures that
+ // TextureSources are recreated.
+ async InvalidateLayers(uint64_t layersId);
+
+ // The compositor type or device has changed, and a new texture factory
+ // identifier is available. Layers must be invalidated and the new identifier
+ // must be propagated.
+ async CompositorUpdated(uint64_t layersId, TextureFactoryIdentifier newIdentifier);
+
+ // The compositor completed a layers transaction. id is the layers id
+ // of the child layer tree that was composited (or 0 when notifying
+ // the root layer tree).
+ // transactionId is the id of the transaction before this composite, or 0
+ // if there was no transaction since the last composite.
+ async DidComposite(uint64_t id, uint64_t transactionId,
+ TimeStamp compositeStart, TimeStamp compositeEnd);
+
+ // The parent sends the child the requested fill ratio numbers.
+ async Overfill(uint32_t aOverfill);
+
+ /**
+ * Parent informs the child that the graphics objects are ready for
+ * compositing. This usually means that the graphics objects (textures
+ * and the like) are available on the GPU. This is used for chrome UI.
+ * @see RequestNotifyAfterRemotePaint
+ * @see PBrowser
+ */
+ async RemotePaintIsReady();
+
+ /**
+ * Bounce plugin widget configurations over to the main thread for
+ * application on the widgets. Used on Windows and Linux in managing
+ * plugin widgets.
+ */
+ async UpdatePluginConfigurations(LayoutDeviceIntPoint aContentOffset,
+ LayoutDeviceIntRegion aVisibleRegion,
+ PluginWindowData[] aPlugins);
+
+ /**
+ * Captures an image for all visible child plugins of a given widget for use
+ * during scrolling.
+ * @param aParentWidget parent of widgets to be captured
+ */
+ async CaptureAllPlugins(uintptr_t aParentWidget);
+
+ /**
+ * Hides all registered plugin widgets associated with a particular chrome
+ * widget.
+ */
+ async HideAllPlugins(uintptr_t aParentWidget);
+
+ /**
+ * Drop any buffers that might be retained on the child compositor
+ * side.
+ */
+ async ClearCachedResources(uint64_t id);
+
+ async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
+
+ async ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive);
+
+parent:
+ // Must be called before Initialize().
+ async PCompositorWidget(CompositorWidgetInitData aInitData);
+
+ // When out-of-process, this must be called to finish initialization.
+ sync Initialize(uint64_t rootLayerTreeId);
+ sync Reset(LayersBackend[] aBackendHints) returns (bool aResult, TextureFactoryIdentifier aOutIdentifier);
+
+ // Returns whether this Compositor has APZ enabled or not.
+ sync AsyncPanZoomEnabled(uint64_t layersId) returns (bool aHasAPZ);
+
+ // Must be called after Initialize(), and only succeeds if AsyncPanZoomEnabled() is true.
+ async PAPZ(uint64_t layersId);
+ async PAPZCTreeManager(uint64_t layersId);
+
+ /**
+ * Confirmation callback for UpdatePluginConfigurations and HideAllPlugins.
+ */
+ async RemotePluginsReady();
+
+ // Confirmation that the child has invalidated all its layers, and will not
+ // request layers against an old compositor.
+ async AcknowledgeCompositorUpdate(uint64_t id);
+
+ // Child sends the parent a request for fill ratio numbers.
+ async RequestOverfill();
+
+ // Child requests frame uniformity measurements
+ sync GetFrameUniformity() returns (FrameUniformityData data);
+
+ // The child is about to be destroyed, so perform any necessary cleanup.
+ sync WillClose();
+
+ // Pause/resume the compositor. These are intended to be used on mobile, when
+ // the compositor needs to pause/resume in lockstep with the application.
+ sync Pause();
+ sync Resume();
+
+ // See bug 1316632 comment #33 for why this has to be sync. Otherwise,
+ // there are ordering issues with SendPLayerTransactionConstructor.
+ sync NotifyChildCreated(uint64_t id);
+
+ async AdoptChild(uint64_t id);
+
+ // Same as NotifyChildCreated, but used when child processes need to
+ // reassociate layers. This must be synchronous to ensure that the
+ // association happens before PLayerTransactions are sent over the
+ // cross-process bridge.
+ sync NotifyChildRecreated(uint64_t id);
+
+ // Make a snapshot of the content that would have been drawn to our
+ // render target at the time this message is received. If the size
+ // or format of |inSnapshot| doesn't match our render target,
+ // results are undefined.
+ //
+ // NB: this message will result in animations, transforms, effects,
+ // and so forth being interpolated. That's what we want to happen.
+ sync MakeSnapshot(SurfaceDescriptor inSnapshot, IntRect dirtyRect);
+
+ // Make sure any pending composites are started immediately and
+ // block until they are completed.
+ sync FlushRendering();
+
+ // Force an additional frame presentation to be executed. This is used to
+ // work around a windows presentation bug (See Bug 1232042)
+ async ForcePresent();
+
+ sync StartFrameTimeRecording(int32_t bufferSize)
+ returns (uint32_t startIndex);
+
+ 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.
+ sync PLayerTransaction(LayersBackend[] layersBackendHints, uint64_t id)
+ returns (TextureFactoryIdentifier textureFactoryIdentifier, bool success);
+
+ // Notify the compositor that a region of the screen has been invalidated.
+ async NotifyRegionInvalidated(nsIntRegion region);
+
+ /**
+ * The child (content/chrome thread) requests that the parent inform it when
+ * the graphics objects are ready to display.
+ * @see PBrowser
+ * @see RemotePaintIsReady
+ */
+ async RequestNotifyAfterRemotePaint();
+
+ // The child clears the 'approximately visible' regions associated with the
+ // provided layers ID and pres shell ID (i.e., the regions for all view IDs
+ // associated with those IDs).
+ async ClearApproximatelyVisibleRegions(uint64_t layersId, uint32_t presShellId);
+
+ // The child sends a region containing rects associated with the provided
+ // scrollable layer GUID that the child considers 'approximately visible'.
+ // We visualize this information in the APZ minimap.
+ async NotifyApproximatelyVisibleRegion(ScrollableLayerGuid guid, CSSIntRegion region);
+
+ /**
+ * Sent when the child has finished CaptureAllPlugins.
+ */
+ async AllPluginsCaptured();
+
+ async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id, uint64_t aSerial);
+
+ sync SyncWithCompositor();
+
+child:
+ // Send back Compositor Frame Metrics from APZCs so tiled layers can
+ // update progressively.
+ async SharedCompositorFrameMetrics(Handle metrics, CrossProcessMutexHandle mutex, uint64_t aLayersId, uint32_t aAPZCId);
+ async ReleaseSharedCompositorFrameMetrics(ViewID aId, uint32_t aAPZCId);
+};
+
+} // layers
+} // mozilla
diff --git a/gfx/layers/ipc/PImageBridge.ipdl b/gfx/layers/ipc/PImageBridge.ipdl
new file mode 100644
index 000000000..3bed222d0
--- /dev/null
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 PCompositable;
+include protocol PImageContainer;
+include protocol PLayer;
+include protocol PTexture;
+include ProtocolTypes;
+include protocol PMediaSystemResourceManager;
+
+include "mozilla/GfxMessageUtils.h";
+
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
+using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
+
+using PlatformThreadId from "base/platform_thread.h";
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * The PImageBridge protocol is used to allow isolated threads or processes to push
+ * frames directly to the compositor thread/process without relying on the main thread
+ * which might be too busy dealing with content script.
+ */
+sync protocol PImageBridge
+{
+ manages PCompositable;
+ manages PTexture;
+ manages PMediaSystemResourceManager;
+ manages PImageContainer;
+
+child:
+ async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
+
+ async DidComposite(ImageCompositeNotification[] aNotifications);
+
+parent:
+ async ImageBridgeThreadId(PlatformThreadId aTreahdId);
+
+ sync Update(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId)
+ returns (EditReply[] reply);
+
+ async UpdateNoSwap(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId);
+
+ // First step of the destruction sequence. This puts ImageBridge
+ // in a state in which it can't send asynchronous messages
+ // so as to not race with the channel getting closed.
+ // In the child side, the Closing the channel does not happen right after WillClose,
+ // it is scheduled in the ImageBridgeChild's message queue in order to ensure
+ // that all of the messages from the parent side have been received and processed
+ // before sending closing the channel.
+ sync WillClose();
+
+ sync PCompositable(TextureInfo aInfo,
+ nullable PImageContainer aImageContainer) returns (uint64_t id);
+ async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t aSerial);
+ async PMediaSystemResourceManager();
+ async PImageContainer();
+
+};
+
+
+} // namespace
+} // namespace
+
diff --git a/gfx/layers/ipc/PImageContainer.ipdl b/gfx/layers/ipc/PImageContainer.ipdl
new file mode 100644
index 000000000..7ae567a88
--- /dev/null
+++ b/gfx/layers/ipc/PImageContainer.ipdl
@@ -0,0 +1,33 @@
+/* -*- 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 protocol PImageBridge;
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * PImageContainer represents an ImageContainer.
+ */
+
+async protocol PImageContainer {
+ manager PImageBridge;
+parent:
+ /**
+ * The child effectively owns the parent. When the child should be
+ * destroyed, it sends an AsyncDelete to the parent but does not die
+ * because we could still have messages in flight from the compositor
+ * mentioning the child. The parent handles AsyncDelete by destroying
+ * itself and sending __delete__ to the child to clean it up.
+ */
+ async AsyncDelete();
+child:
+ async __delete__();
+};
+
+} // layers
+} // mozilla
diff --git a/gfx/layers/ipc/PLayer.ipdl b/gfx/layers/ipc/PLayer.ipdl
new file mode 100644
index 000000000..4a46b56d6
--- /dev/null
+++ b/gfx/layers/ipc/PLayer.ipdl
@@ -0,0 +1,39 @@
+/* -*- 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 protocol PLayerTransaction;
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * PLayer represents a layer shared across thread contexts.
+ */
+
+async protocol PLayer {
+ manager PLayerTransaction;
+
+ /**
+ * OWNERSHIP MODEL
+ *
+ * Roughly speaking, the child side "actually owns" a Layer. This
+ * is because the parent side is the "shadow"; when the child
+ * releases a Layer, the parent's shadow is no longer meaningful.
+ *
+ * To implement this model, the concrete PLayerParent keeps a
+ * strong ref to its Layer, so the Layer's lifetime is bound to
+ * the PLayerParent's. Then, when the Layer's refcount hits 0 on
+ * the child side, we send __delete__() from the child to parent.
+ * The parent then releases its Layer, which results in the Layer
+ * being deleted "soon" (usually immediately).
+ */
+parent:
+ async __delete__();
+};
+
+} // layers
+} // mozilla
diff --git a/gfx/layers/ipc/PLayerTransaction.ipdl b/gfx/layers/ipc/PLayerTransaction.ipdl
new file mode 100644
index 000000000..d669b1d65
--- /dev/null
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -0,0 +1,133 @@
+/* -*- 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 PCompositable;
+include protocol PCompositorBridge;
+include protocol PLayer;
+include protocol PRenderFrame;
+include protocol PTexture;
+
+include "mozilla/GfxMessageUtils.h";
+
+using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h";
+using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
+using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
+using mozilla::layers::LayersBackend 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 {
+
+union MaybeTransform {
+ Matrix4x4;
+ void_t;
+};
+
+sync protocol PLayerTransaction {
+ manager PCompositorBridge;
+ manages PLayer;
+ manages PCompositable;
+
+parent:
+ async PLayer();
+ async PCompositable(TextureInfo aTextureInfo);
+
+ // The isFirstPaint flag can be used to indicate that this is the first update
+ // for a particular document.
+ sync Update(Edit[] cset, OpDestroy[] toDestroy,
+ uint64_t fwdTransactionId,
+ uint64_t id, TargetConfig targetConfig,
+ PluginWindowData[] plugins, bool isFirstPaint,
+ bool scheduleComposite, uint32_t paintSequenceNumber,
+ bool isRepeatTransaction, TimeStamp transactionStart,
+ int32_t paintSyncId)
+ returns (EditReply[] reply);
+
+ async PaintTime(uint64_t id, TimeDuration paintTime);
+
+ // We don't need to send a sync transaction if
+ // no transaction operate require a swap.
+ async UpdateNoSwap(Edit[] cset, OpDestroy[] toDestroy,
+ uint64_t fwdTransactionId,
+ uint64_t id, TargetConfig targetConfig,
+ PluginWindowData[] plugins, bool isFirstPaint,
+ bool scheduleComposite, uint32_t paintSequenceNumber,
+ bool isRepeatTransaction, TimeStamp transactionStart,
+ int32_t paintSyncId);
+
+ async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
+
+ // 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 the value of the opacity applied to the layer by animation.
+ // |hasAnimationOpacity| is true if the layer has an opacity value
+ // specified by animation. If it's false, |opacity| value is indefinite.
+ sync GetAnimationOpacity(PLayer layer) returns (float opacity,
+ bool hasAnimationOpacity);
+
+ // Returns the value of the transform applied to the layer by animation after
+ // factoring out translation components introduced to account for the offset
+ // of the corresponding frame and transform origin and after converting to CSS
+ // pixels. If the layer is not transformed by animation, the return value will
+ // be void_t.
+ sync GetAnimationTransform(PLayer layer) returns (MaybeTransform 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 ForceComposite();
+
+ // Get a copy of the compositor-side APZ test data instance for this
+ // layers id.
+ sync GetAPZTestData() returns (APZTestData data);
+
+ // Query a named property from the last frame
+ sync RequestProperty(nsString property) returns (float value);
+
+ // Tell the compositor to notify APZ that a layer has been confirmed for an
+ // input event.
+ async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
+
+ async Shutdown();
+child:
+ async __delete__();
+};
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/PTexture.ipdl b/gfx/layers/ipc/PTexture.ipdl
new file mode 100644
index 000000000..bccff8627
--- /dev/null
+++ b/gfx/layers/ipc/PTexture.ipdl
@@ -0,0 +1,46 @@
+/* -*- 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 protocol PLayerTransaction;
+include protocol PCompositorBridge;
+include protocol PImageBridge;
+include protocol PVRManager;
+include protocol PVideoBridge;
+include "mozilla/GfxMessageUtils.h";
+
+using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * PTexture is the IPDL glue between a TextureClient and a TextureHost.
+ */
+sync protocol PTexture {
+ manager PImageBridge or PCompositorBridge or PVRManager or PVideoBridge;
+
+child:
+ async __delete__();
+
+parent:
+ /**
+ * Asynchronously tell the compositor side to remove the texture.
+ */
+ async Destroy();
+
+ /**
+ * Synchronously tell the compositor side to remove the texture.
+ */
+ sync DestroySync();
+
+ async RecycleTexture(TextureFlags aTextureFlags);
+};
+
+} // layers
+} // mozilla
diff --git a/gfx/layers/ipc/PVideoBridge.ipdl b/gfx/layers/ipc/PVideoBridge.ipdl
new file mode 100644
index 000000000..3fca7ac75
--- /dev/null
+++ b/gfx/layers/ipc/PVideoBridge.ipdl
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 PTexture;
+
+include "mozilla/GfxMessageUtils.h";
+using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * The PVideoBridge protocol is used to share textures from the video decoders
+ * to the compositor.
+ */
+sync protocol PVideoBridge
+{
+ manages PTexture;
+
+parent:
+ async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend,
+ TextureFlags aTextureFlags, uint64_t aSerial);
+};
+
+} // namespace
+} // namespace
+
diff --git a/gfx/layers/ipc/RemoteContentController.cpp b/gfx/layers/ipc/RemoteContentController.cpp
new file mode 100644
index 000000000..54a08eed3
--- /dev/null
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -0,0 +1,272 @@
+/* -*- 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 "mozilla/layers/RemoteContentController.h"
+
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "MainThreadUtils.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/TabParent.h"
+#include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
+#include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layout/RenderFrameParent.h"
+#include "mozilla/gfx/GPUProcessManager.h"
+#include "mozilla/Unused.h"
+#include "Units.h"
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidBridge.h"
+#endif
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+RemoteContentController::RemoteContentController()
+ : mCompositorThread(MessageLoop::current())
+ , mCanSend(true)
+{
+}
+
+RemoteContentController::~RemoteContentController()
+{
+}
+
+void
+RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
+{
+ MOZ_ASSERT(IsRepaintThread());
+
+ if (mCanSend) {
+ Unused << SendRequestContentRepaint(aFrameMetrics);
+ }
+}
+
+void
+RemoteContentController::HandleTapOnMainThread(TapType aTapType,
+ LayoutDevicePoint aPoint,
+ Modifiers aModifiers,
+ ScrollableLayerGuid aGuid,
+ uint64_t aInputBlockId)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ dom::TabParent* tab = dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
+ if (tab) {
+ tab->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
+ }
+}
+
+void
+RemoteContentController::HandleTap(TapType aTapType,
+ const LayoutDevicePoint& aPoint,
+ Modifiers aModifiers,
+ const ScrollableLayerGuid& aGuid,
+ uint64_t aInputBlockId)
+{
+ APZThreadUtils::AssertOnControllerThread();
+
+ if (XRE_GetProcessType() == GeckoProcessType_GPU) {
+ MOZ_ASSERT(MessageLoop::current() == mCompositorThread);
+
+ // The raw pointer to APZCTreeManagerParent is ok here because we are on the
+ // compositor thread.
+ APZCTreeManagerParent* apzctmp =
+ CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
+ if (apzctmp) {
+ Unused << apzctmp->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
+ }
+
+ return;
+ }
+
+ MOZ_ASSERT(XRE_IsParentProcess());
+
+ if (NS_IsMainThread()) {
+ HandleTapOnMainThread(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
+ } else {
+ // We don't want to get the TabParent or call TabParent::SendHandleTap() from a non-main thread (this might happen
+ // on Android, where this is called from the Java UI thread)
+ NS_DispatchToMainThread(NewRunnableMethod<TapType, LayoutDevicePoint, Modifiers, ScrollableLayerGuid, uint64_t>
+ (this, &RemoteContentController::HandleTapOnMainThread, aTapType, aPoint, aModifiers, aGuid, aInputBlockId));
+ }
+}
+
+void
+RemoteContentController::NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
+ const ScrollableLayerGuid& aGuid,
+ LayoutDeviceCoord aSpanChange,
+ Modifiers aModifiers)
+{
+ APZThreadUtils::AssertOnControllerThread();
+
+ // For now we only ever want to handle this NotifyPinchGesture message in
+ // the parent process, even if the APZ is sending it to a content process.
+
+ // If we're in the GPU process, try to find a handle to the parent process
+ // and send it there.
+ if (XRE_IsGPUProcess()) {
+ MOZ_ASSERT(MessageLoop::current() == mCompositorThread);
+
+ // The raw pointer to APZCTreeManagerParent is ok here because we are on the
+ // compositor thread.
+ APZCTreeManagerParent* apzctmp =
+ CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
+ if (apzctmp) {
+ Unused << apzctmp->SendNotifyPinchGesture(aType, aGuid, aSpanChange, aModifiers);
+ return;
+ }
+ }
+
+ // If we're in the parent process, handle it directly. We don't have a handle
+ // to the widget though, so we fish out the ChromeProcessController and
+ // delegate to that instead.
+ if (XRE_IsParentProcess()) {
+ MOZ_ASSERT(NS_IsMainThread());
+ RefPtr<GeckoContentController> rootController =
+ CompositorBridgeParent::GetGeckoContentControllerForRoot(aGuid.mLayersId);
+ if (rootController) {
+ rootController->NotifyPinchGesture(aType, aGuid, aSpanChange, aModifiers);
+ }
+ }
+}
+
+void
+RemoteContentController::PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs)
+{
+#ifdef MOZ_WIDGET_ANDROID
+ AndroidBridge::Bridge()->PostTaskToUiThread(Move(aTask), aDelayMs);
+#else
+ (MessageLoop::current() ? MessageLoop::current() : mCompositorThread)->
+ PostDelayedTask(Move(aTask), aDelayMs);
+#endif
+}
+
+bool
+RemoteContentController::IsRepaintThread()
+{
+ return MessageLoop::current() == mCompositorThread;
+}
+
+void
+RemoteContentController::DispatchToRepaintThread(already_AddRefed<Runnable> aTask)
+{
+ mCompositorThread->PostTask(Move(aTask));
+}
+
+void
+RemoteContentController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
+ APZStateChange aChange,
+ int aArg)
+{
+ if (MessageLoop::current() != mCompositorThread) {
+ // We have to send messages from the compositor thread
+ mCompositorThread->PostTask(NewRunnableMethod<ScrollableLayerGuid,
+ APZStateChange,
+ int>(this,
+ &RemoteContentController::NotifyAPZStateChange,
+ aGuid, aChange, aArg));
+ return;
+ }
+
+ if (mCanSend) {
+ Unused << SendNotifyAPZStateChange(aGuid, aChange, aArg);
+ }
+}
+
+void
+RemoteContentController::UpdateOverscrollVelocity(float aX, float aY, bool aIsRootContent)
+{
+ if (MessageLoop::current() != mCompositorThread) {
+ mCompositorThread->PostTask(NewRunnableMethod<float,
+ float, bool>(this,
+ &RemoteContentController::UpdateOverscrollVelocity,
+ aX, aY, aIsRootContent));
+ return;
+ }
+ if (mCanSend) {
+ Unused << SendUpdateOverscrollVelocity(aX, aY, aIsRootContent);
+ }
+}
+
+void
+RemoteContentController::UpdateOverscrollOffset(float aX, float aY, bool aIsRootContent)
+{
+ if (MessageLoop::current() != mCompositorThread) {
+ mCompositorThread->PostTask(NewRunnableMethod<float,
+ float, bool>(this,
+ &RemoteContentController::UpdateOverscrollOffset,
+ aX, aY, aIsRootContent));
+ return;
+ }
+ if (mCanSend) {
+ Unused << SendUpdateOverscrollOffset(aX, aY, aIsRootContent);
+ }
+}
+
+void
+RemoteContentController::SetScrollingRootContent(bool aIsRootContent)
+{
+ if (MessageLoop::current() != mCompositorThread) {
+ mCompositorThread->PostTask(NewRunnableMethod<bool>(this,
+ &RemoteContentController::SetScrollingRootContent,
+ aIsRootContent));
+ return;
+ }
+ if (mCanSend) {
+ Unused << SendSetScrollingRootContent(aIsRootContent);
+ }
+}
+
+void
+RemoteContentController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
+ const nsString& aEvent)
+{
+ if (MessageLoop::current() != mCompositorThread) {
+ // We have to send messages from the compositor thread
+ mCompositorThread->PostTask(NewRunnableMethod<FrameMetrics::ViewID,
+ nsString>(this,
+ &RemoteContentController::NotifyMozMouseScrollEvent,
+ aScrollId, aEvent));
+ return;
+ }
+
+ if (mCanSend) {
+ Unused << SendNotifyMozMouseScrollEvent(aScrollId, aEvent);
+ }
+}
+
+void
+RemoteContentController::NotifyFlushComplete()
+{
+ MOZ_ASSERT(IsRepaintThread());
+
+ if (mCanSend) {
+ Unused << SendNotifyFlushComplete();
+ }
+}
+
+void
+RemoteContentController::ActorDestroy(ActorDestroyReason aWhy)
+{
+ // This controller could possibly be kept alive longer after this
+ // by a RefPtr, but it is no longer valid to send messages.
+ mCanSend = false;
+}
+
+void
+RemoteContentController::Destroy()
+{
+ if (mCanSend) {
+ mCanSend = false;
+ Unused << SendDestroy();
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/RemoteContentController.h b/gfx/layers/ipc/RemoteContentController.h
new file mode 100644
index 000000000..d015ada4f
--- /dev/null
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -0,0 +1,96 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_RemoteContentController_h
+#define mozilla_layers_RemoteContentController_h
+
+#include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/PAPZParent.h"
+
+namespace mozilla {
+
+namespace dom {
+class TabParent;
+}
+
+namespace layers {
+
+/**
+ * RemoteContentController implements PAPZChild and is used to access a
+ * GeckoContentController that lives in a different process.
+ *
+ * RemoteContentController lives on the compositor thread. All methods can
+ * be called off the compositor thread and will get dispatched to the right
+ * thread, with the exception of RequestContentRepaint and NotifyFlushComplete,
+ * which must be called on the repaint thread, which in this case is the compositor
+ * thread.
+ */
+class RemoteContentController : public GeckoContentController
+ , public PAPZParent
+{
+ using GeckoContentController::TapType;
+ using GeckoContentController::APZStateChange;
+
+public:
+ RemoteContentController();
+
+ virtual ~RemoteContentController();
+
+ virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
+
+ virtual void HandleTap(TapType aTapType,
+ const LayoutDevicePoint& aPoint,
+ Modifiers aModifiers,
+ const ScrollableLayerGuid& aGuid,
+ uint64_t aInputBlockId) override;
+
+ virtual void NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
+ const ScrollableLayerGuid& aGuid,
+ LayoutDeviceCoord aSpanChange,
+ Modifiers aModifiers) override;
+
+ virtual void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) override;
+
+ virtual bool IsRepaintThread() override;
+
+ virtual void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) override;
+
+ virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
+ APZStateChange aChange,
+ int aArg) override;
+
+ virtual void UpdateOverscrollVelocity(float aX, float aY, bool aIsRootContent) override;
+
+ virtual void UpdateOverscrollOffset(float aX, float aY, bool aIsRootContent) override;
+
+ virtual void SetScrollingRootContent(bool aIsRootContent) override;
+
+ virtual void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId,
+ const nsString& aEvent) override;
+
+ virtual void NotifyFlushComplete() override;
+
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ virtual void Destroy() override;
+
+private:
+ MessageLoop* mCompositorThread;
+ bool mCanSend;
+
+ void HandleTapOnMainThread(TapType aType,
+ LayoutDevicePoint aPoint,
+ Modifiers aModifiers,
+ ScrollableLayerGuid aGuid,
+ uint64_t aInputBlockId);
+};
+
+} // namespace layers
+
+} // namespace mozilla
+
+#endif // mozilla_layers_RemoteContentController_h
diff --git a/gfx/layers/ipc/ShadowLayerChild.cpp b/gfx/layers/ipc/ShadowLayerChild.cpp
new file mode 100644
index 000000000..62d260838
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerChild.cpp
@@ -0,0 +1,45 @@
+/* -*- 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 "ShadowLayerChild.h"
+#include "Layers.h" // for Layer
+#include "ShadowLayers.h" // for ShadowableLayer
+
+namespace mozilla {
+namespace layers {
+
+ShadowLayerChild::ShadowLayerChild()
+ : mLayer(nullptr)
+{ }
+
+ShadowLayerChild::~ShadowLayerChild()
+{ }
+
+void
+ShadowLayerChild::SetShadowableLayer(ShadowableLayer* aLayer)
+{
+ MOZ_ASSERT(!mLayer);
+ mLayer = aLayer;
+}
+
+void
+ShadowLayerChild::ActorDestroy(ActorDestroyReason why)
+{
+ MOZ_ASSERT(AncestorDeletion != why,
+ "shadowable layer should have been cleaned up by now");
+
+ if (AbnormalShutdown == why && mLayer) {
+ // This is last-ditch emergency shutdown. Just have the layer
+ // forget its IPDL resources; IPDL-generated code will clean up
+ // automatically in this case.
+ mLayer->AsLayer()->Disconnect();
+ mLayer = nullptr;
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ShadowLayerChild.h b/gfx/layers/ipc/ShadowLayerChild.h
new file mode 100644
index 000000000..38a7f9500
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerChild.h
@@ -0,0 +1,39 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_ShadowLayerChild_h
+#define mozilla_layers_ShadowLayerChild_h
+
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/PLayerChild.h" // for PLayerChild
+
+namespace mozilla {
+namespace layers {
+
+class ShadowableLayer;
+
+class ShadowLayerChild : public PLayerChild
+{
+public:
+ ShadowLayerChild();
+ virtual ~ShadowLayerChild();
+
+ void SetShadowableLayer(ShadowableLayer* aLayer);
+ ShadowableLayer* layer() const { return mLayer; }
+
+protected:
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+private:
+ ShadowableLayer* mLayer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_ShadowLayerChild_h
diff --git a/gfx/layers/ipc/ShadowLayerParent.cpp b/gfx/layers/ipc/ShadowLayerParent.cpp
new file mode 100644
index 000000000..e0898715d
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerParent.cpp
@@ -0,0 +1,138 @@
+/* -*- 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 "ShadowLayerParent.h"
+#include "Layers.h" // for Layer, ContainerLayer
+#include "nsDebug.h" // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h" // for Layer::AddRef, etc
+
+#include "mozilla/layers/PaintedLayerComposite.h"
+#include "mozilla/layers/CanvasLayerComposite.h"
+#include "mozilla/layers/ColorLayerComposite.h"
+#include "mozilla/layers/ImageLayerComposite.h"
+#include "mozilla/layers/ContainerLayerComposite.h"
+
+namespace mozilla {
+namespace layers {
+
+ShadowLayerParent::ShadowLayerParent() : mLayer(nullptr)
+{
+}
+
+ShadowLayerParent::~ShadowLayerParent()
+{
+ Disconnect();
+}
+
+void
+ShadowLayerParent::Disconnect()
+{
+ if (mLayer) {
+ mLayer->Disconnect();
+ mLayer = nullptr;
+ }
+}
+
+void
+ShadowLayerParent::Bind(Layer* layer)
+{
+ if (mLayer != layer) {
+ Disconnect();
+ mLayer = layer;
+ }
+}
+
+void
+ShadowLayerParent::Destroy()
+{
+ // It's possible for Destroy() to come in just after this has been
+ // created, but just before the transaction in which Bind() would
+ // have been called. In that case, we'll ignore shadow-layers
+ // transactions from there on and never get a layer here.
+ Disconnect();
+}
+
+ContainerLayerComposite*
+ShadowLayerParent::AsContainerLayerComposite() const
+{
+ return mLayer && mLayer->GetType() == Layer::TYPE_CONTAINER
+ ? static_cast<ContainerLayerComposite*>(mLayer.get())
+ : nullptr;
+}
+
+CanvasLayerComposite*
+ShadowLayerParent::AsCanvasLayerComposite() const
+{
+ return mLayer && mLayer->GetType() == Layer::TYPE_CANVAS
+ ? static_cast<CanvasLayerComposite*>(mLayer.get())
+ : nullptr;
+}
+
+ColorLayerComposite*
+ShadowLayerParent::AsColorLayerComposite() const
+{
+ return mLayer && mLayer->GetType() == Layer::TYPE_COLOR
+ ? static_cast<ColorLayerComposite*>(mLayer.get())
+ : nullptr;
+}
+
+ImageLayerComposite*
+ShadowLayerParent::AsImageLayerComposite() const
+{
+ return mLayer && mLayer->GetType() == Layer::TYPE_IMAGE
+ ? static_cast<ImageLayerComposite*>(mLayer.get())
+ : nullptr;
+}
+
+RefLayerComposite*
+ShadowLayerParent::AsRefLayerComposite() const
+{
+ return mLayer && mLayer->GetType() == Layer::TYPE_REF
+ ? static_cast<RefLayerComposite*>(mLayer.get())
+ : nullptr;
+}
+
+PaintedLayerComposite*
+ShadowLayerParent::AsPaintedLayerComposite() const
+{
+ return mLayer && mLayer->GetType() == Layer::TYPE_PAINTED
+ ? static_cast<PaintedLayerComposite*>(mLayer.get())
+ : nullptr;
+}
+
+void
+ShadowLayerParent::ActorDestroy(ActorDestroyReason why)
+{
+ switch (why) {
+ case AncestorDeletion:
+ NS_RUNTIMEABORT("shadow layer deleted out of order!");
+ return; // unreached
+
+ case Deletion:
+ // See comment near Destroy() above.
+ Disconnect();
+ break;
+
+ case AbnormalShutdown:
+ Disconnect();
+ break;
+
+ case NormalShutdown:
+ // let IPDL-generated code automatically clean up Shmems and so
+ // forth; our channel is disconnected anyway
+ break;
+
+ case FailedConstructor:
+ NS_RUNTIMEABORT("FailedConstructor isn't possible in PLayerTransaction");
+ return; // unreached
+ }
+
+ mLayer = nullptr;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ShadowLayerParent.h b/gfx/layers/ipc/ShadowLayerParent.h
new file mode 100644
index 000000000..d40cf34ff
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerParent.h
@@ -0,0 +1,58 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_ShadowLayerParent_h
+#define mozilla_layers_ShadowLayerParent_h
+
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/PLayerParent.h" // for PLayerParent
+
+namespace mozilla {
+namespace layers {
+
+class ContainerLayer;
+class Layer;
+
+class CanvasLayerComposite;
+class ColorLayerComposite;
+class ContainerLayerComposite;
+class ImageLayerComposite;
+class RefLayerComposite;
+class PaintedLayerComposite;
+
+class ShadowLayerParent : public PLayerParent
+{
+public:
+ ShadowLayerParent();
+
+ virtual ~ShadowLayerParent();
+
+ void Bind(Layer* layer);
+ void Destroy();
+
+ Layer* AsLayer() const { return mLayer; }
+
+ ContainerLayerComposite* AsContainerLayerComposite() const;
+ CanvasLayerComposite* AsCanvasLayerComposite() const;
+ ColorLayerComposite* AsColorLayerComposite() const;
+ ImageLayerComposite* AsImageLayerComposite() const;
+ RefLayerComposite* AsRefLayerComposite() const;
+ PaintedLayerComposite* AsPaintedLayerComposite() const;
+
+private:
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ void Disconnect();
+
+ RefPtr<Layer> mLayer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_ShadowLayerParent_h
diff --git a/gfx/layers/ipc/ShadowLayerUtils.h b/gfx/layers/ipc/ShadowLayerUtils.h
new file mode 100644
index 000000000..257cee81d
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtils.h
@@ -0,0 +1,52 @@
+/* -*- 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/. */
+
+#ifndef IPC_ShadowLayerUtils_h
+#define IPC_ShadowLayerUtils_h
+
+#include "ipc/IPCMessageUtils.h"
+#include "GLContextTypes.h"
+#include "SurfaceTypes.h"
+#include "mozilla/WidgetUtils.h"
+
+#if defined(XP_MACOSX)
+#define MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
+#endif
+
+#if defined(MOZ_X11)
+# include "mozilla/layers/ShadowLayerUtilsX11.h"
+#else
+namespace mozilla { namespace layers {
+struct SurfaceDescriptorX11 {
+ bool operator==(const SurfaceDescriptorX11&) const { return false; }
+};
+} // namespace layers
+} // namespace mozilla
+#endif
+
+namespace IPC {
+
+#if !defined(MOZ_HAVE_SURFACEDESCRIPTORX11)
+template <>
+struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
+ typedef mozilla::layers::SurfaceDescriptorX11 paramType;
+ static void Write(Message*, const paramType&) {}
+ static bool Read(const Message*, PickleIterator*, paramType*) { return false; }
+};
+#endif // !defined(MOZ_HAVE_XSURFACEDESCRIPTORX11)
+
+template <>
+struct ParamTraits<mozilla::ScreenRotation>
+ : public ContiguousEnumSerializer<
+ mozilla::ScreenRotation,
+ mozilla::ROTATION_0,
+ mozilla::ROTATION_COUNT>
+{};
+
+} // namespace IPC
+
+#endif // IPC_ShadowLayerUtils_h
diff --git a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
new file mode 100644
index 000000000..cc5199ea8
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
@@ -0,0 +1,40 @@
+/* -*- 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 "mozilla/gfx/Point.h"
+#include "mozilla/layers/PLayerTransaction.h"
+#include "mozilla/layers/ShadowLayers.h"
+#include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/CompositorTypes.h"
+
+#include "gfx2DGlue.h"
+#include "gfxPlatform.h"
+
+using namespace mozilla::gl;
+
+namespace mozilla {
+namespace layers {
+
+/*static*/ void
+ShadowLayerForwarder::PlatformSyncBeforeUpdate()
+{
+}
+
+/*static*/ void
+LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
+{
+}
+
+/*static*/ bool
+LayerManagerComposite::SupportsDirectTexturing()
+{
+ return false;
+}
+
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
new file mode 100644
index 000000000..6b9660054
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -0,0 +1,153 @@
+/* -*- 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 "ShadowLayerUtilsX11.h"
+#include <X11/X.h> // for Drawable, XID
+#include <X11/Xlib.h> // for Display, Visual, etc
+#include <X11/extensions/Xrender.h> // for XRenderPictFormat, etc
+#include <X11/extensions/render.h> // for PictFormat
+#include "cairo-xlib.h"
+#include "X11UndefineNone.h"
+#include <stdint.h> // for uint32_t
+#include "GLDefs.h" // for GLenum
+#include "gfxPlatform.h" // for gfxPlatform
+#include "gfxXlibSurface.h" // for gfxXlibSurface
+#include "gfx2DGlue.h" // for Moz2D transistion helpers
+#include "mozilla/X11Util.h" // for DefaultXDisplay, FinishX, etc
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorTypes.h" // for OpenMode
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator, etc
+#include "mozilla/layers/LayerManagerComposite.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
+#include "nsDebug.h" // for NS_ERROR
+
+using namespace mozilla::gl;
+
+namespace mozilla {
+namespace gl {
+class GLContext;
+class TextureImage;
+}
+
+namespace layers {
+
+// Return true if we're likely compositing using X and so should use
+// Xlib surfaces in shadow layers.
+static bool
+UsingXCompositing()
+{
+ if (!gfxEnv::LayersEnableXlibSurfaces()) {
+ return false;
+ }
+ return (gfxSurfaceType::Xlib ==
+ gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType());
+}
+
+// LookReturn a pointer to |aFormat| that lives in the Xrender library.
+// All code using render formats assumes it doesn't need to copy.
+static XRenderPictFormat*
+GetXRenderPictFormatFromId(Display* aDisplay, PictFormat aFormatId)
+{
+ XRenderPictFormat tmplate;
+ tmplate.id = aFormatId;
+ return XRenderFindFormat(aDisplay, PictFormatID, &tmplate, 0);
+}
+
+SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf,
+ bool aForwardGLX)
+ : mId(aSurf->XDrawable())
+ , mSize(aSurf->GetSize())
+ , mGLXPixmap(X11None)
+{
+ const XRenderPictFormat *pictFormat = aSurf->XRenderFormat();
+ if (pictFormat) {
+ mFormat = pictFormat->id;
+ } else {
+ mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid;
+ }
+
+#ifdef GL_PROVIDER_GLX
+ if (aForwardGLX) {
+ mGLXPixmap = aSurf->GetGLXPixmap();
+ }
+#endif
+}
+
+SurfaceDescriptorX11::SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
+ const gfx::IntSize& aSize)
+ : mId(aDrawable)
+ , mFormat(aFormatID)
+ , mSize(aSize)
+ , mGLXPixmap(X11None)
+{ }
+
+already_AddRefed<gfxXlibSurface>
+SurfaceDescriptorX11::OpenForeign() const
+{
+ Display* display = DefaultXDisplay();
+ Screen* screen = DefaultScreenOfDisplay(display);
+
+ RefPtr<gfxXlibSurface> surf;
+ XRenderPictFormat* pictFormat = GetXRenderPictFormatFromId(display, mFormat);
+ if (pictFormat) {
+ surf = new gfxXlibSurface(screen, mId, pictFormat, mSize);
+ } else {
+ Visual* visual;
+ int depth;
+ FindVisualAndDepth(display, mFormat, &visual, &depth);
+ if (!visual)
+ return nullptr;
+
+ surf = new gfxXlibSurface(display, mId, visual, mSize);
+ }
+
+#ifdef GL_PROVIDER_GLX
+ if (mGLXPixmap)
+ surf->BindGLXPixmap(mGLXPixmap);
+#endif
+
+ 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()) {
+ // If we're using X surfaces, we need to finish all pending
+ // operations on the *front buffers* before handing them back to
+ // the child, even though they will be read operations.
+ // Otherwise, the child might start scribbling on new back buffers
+ // that are still participating in requests as old front buffers.
+ FinishX(DefaultXDisplay());
+ }
+}
+
+/*static*/ bool
+LayerManagerComposite::SupportsDirectTexturing()
+{
+ return false;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ShadowLayerUtilsX11.h b/gfx/layers/ipc/ShadowLayerUtilsX11.h
new file mode 100644
index 000000000..bf64b09ff
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.h
@@ -0,0 +1,85 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_ShadowLayerUtilsX11_h
+#define mozilla_layers_ShadowLayerUtilsX11_h
+
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/GfxMessageUtils.h"
+#include "nsCOMPtr.h" // for already_AddRefed
+
+#define MOZ_HAVE_SURFACEDESCRIPTORX11
+#define MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
+
+typedef unsigned long XID;
+typedef XID Drawable;
+
+class gfxXlibSurface;
+
+namespace IPC {
+class Message;
+}
+
+namespace mozilla {
+namespace layers {
+
+struct SurfaceDescriptorX11 {
+ SurfaceDescriptorX11()
+ { }
+
+ explicit SurfaceDescriptorX11(gfxXlibSurface* aSurf, bool aForwardGLX = false);
+
+ SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
+ const gfx::IntSize& aSize);
+
+ // Default copy ctor and operator= are OK
+
+ bool operator==(const SurfaceDescriptorX11& aOther) const {
+ // Define == as two descriptors having the same XID for now,
+ // ignoring size and render format. If the two indeed refer to
+ // the same valid XID, then size/format are "actually" the same
+ // anyway, regardless of the values of the fields in
+ // SurfaceDescriptorX11.
+ return mId == aOther.mId;
+ }
+
+ already_AddRefed<gfxXlibSurface> OpenForeign() const;
+
+ MOZ_INIT_OUTSIDE_CTOR Drawable mId;
+ MOZ_INIT_OUTSIDE_CTOR XID mFormat; // either a PictFormat or VisualID
+ MOZ_INIT_OUTSIDE_CTOR gfx::IntSize mSize;
+ MOZ_INIT_OUTSIDE_CTOR Drawable mGLXPixmap; // used to prevent multiple bindings to the same GLXPixmap in-process
+};
+
+} // namespace layers
+} // namespace mozilla
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
+ typedef mozilla::layers::SurfaceDescriptorX11 paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam) {
+ WriteParam(aMsg, aParam.mId);
+ WriteParam(aMsg, aParam.mSize);
+ WriteParam(aMsg, aParam.mFormat);
+ WriteParam(aMsg, aParam.mGLXPixmap);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
+ return (ReadParam(aMsg, aIter, &aResult->mId) &&
+ ReadParam(aMsg, aIter, &aResult->mSize) &&
+ ReadParam(aMsg, aIter, &aResult->mFormat) &&
+ ReadParam(aMsg, aIter, &aResult->mGLXPixmap)
+ );
+ }
+};
+
+} // namespace IPC
+
+#endif // mozilla_layers_ShadowLayerUtilsX11_h
diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp
new file mode 100644
index 000000000..88b88bde0
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -0,0 +1,1044 @@
+/* -*- 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 "ClientLayerManager.h" // for ClientLayerManager
+#include "ShadowLayers.h"
+#include <set> // for _Rb_tree_const_iterator, etc
+#include <vector> // for vector
+#include "GeckoProfiler.h" // for PROFILER_LABEL
+#include "ISurfaceAllocator.h" // for IsSurfaceDescriptorValid
+#include "Layers.h" // for Layer
+#include "RenderTrace.h" // for RenderTraceScope
+#include "ShadowLayerChild.h" // for ShadowLayerChild
+#include "gfx2DGlue.h" // for Moz2D transition helpers
+#include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform
+//#include "gfxSharedImageSurface.h" // for gfxSharedImageSurface
+#include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t
+#include "IPDLActor.h"
+#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/ImageDataSerializer.h"
+#include "mozilla/layers/ImageBridgeChild.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/LayerTransactionChild.h"
+#include "mozilla/layers/PCompositableChild.h"
+#include "mozilla/layers/PTextureChild.h"
+#include "ShadowLayerUtils.h"
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "nsTArray.h" // for AutoTArray, nsTArray, etc
+#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
+#include "mozilla/ReentrantMonitor.h"
+
+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<SurfaceDescriptor> BufferArray;
+typedef std::vector<Edit> EditVector;
+typedef nsTHashtable<nsPtrHashKey<ShadowableLayer>> ShadowableLayerSet;
+typedef nsTArray<OpDestroy> OpDestroyVector;
+
+class Transaction
+{
+public:
+ Transaction()
+ : mTargetRotation(ROTATION_0)
+ , mSwapRequired(false)
+ , mOpen(false)
+ , mRotationChanged(false)
+ {}
+
+ void Begin(const gfx::IntRect& aTargetBounds, ScreenRotation aRotation,
+ dom::ScreenOrientationInternal 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 MarkSyncTransaction()
+ {
+ mSwapRequired = true;
+ }
+ void AddEdit(const Edit& aEdit)
+ {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mCset.push_back(aEdit);
+ }
+ void AddEdit(const CompositableOperation& aEdit)
+ {
+ AddEdit(Edit(aEdit));
+ }
+ void AddPaint(const Edit& aPaint)
+ {
+ AddNoSwapPaint(aPaint);
+ mSwapRequired = true;
+ }
+ void AddPaint(const CompositableOperation& aPaint)
+ {
+ AddNoSwapPaint(Edit(aPaint));
+ mSwapRequired = true;
+ }
+
+ void AddNoSwapPaint(const Edit& aPaint)
+ {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mPaints.push_back(aPaint);
+ }
+ void AddNoSwapPaint(const CompositableOperation& aPaint)
+ {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mPaints.push_back(Edit(aPaint));
+ }
+ void AddMutant(ShadowableLayer* aLayer)
+ {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mMutants.PutEntry(aLayer);
+ }
+ void End()
+ {
+ mCset.clear();
+ mPaints.clear();
+ mMutants.Clear();
+ mDestroyedActors.Clear();
+ mOpen = false;
+ mSwapRequired = false;
+ mRotationChanged = false;
+ }
+
+ bool Empty() const {
+ return mCset.empty() && mPaints.empty() && mMutants.IsEmpty()
+ && mDestroyedActors.IsEmpty();
+ }
+ bool RotationChanged() const {
+ return mRotationChanged;
+ }
+ bool Finished() const { return !mOpen && Empty(); }
+
+ bool Opened() const { return mOpen; }
+
+ EditVector mCset;
+ EditVector mPaints;
+ OpDestroyVector mDestroyedActors;
+ ShadowableLayerSet mMutants;
+ gfx::IntRect mTargetBounds;
+ ScreenRotation mTargetRotation;
+ dom::ScreenOrientationInternal mTargetOrientation;
+ bool mSwapRequired;
+
+private:
+ bool mOpen;
+ bool mRotationChanged;
+
+ // disabled
+ Transaction(const Transaction&);
+ Transaction& operator=(const Transaction&);
+};
+struct AutoTxnEnd {
+ explicit AutoTxnEnd(Transaction* aTxn) : mTxn(aTxn) {}
+ ~AutoTxnEnd() { mTxn->End(); }
+ Transaction* mTxn;
+};
+
+void
+KnowsCompositor::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
+{
+ mTextureFactoryIdentifier = aIdentifier;
+
+ mSyncObject = SyncObject::CreateSyncObject(aIdentifier.mSyncHandle);
+}
+
+KnowsCompositor::KnowsCompositor()
+ : mSerial(++sSerialCounter)
+{}
+
+KnowsCompositor::~KnowsCompositor()
+{}
+
+ShadowLayerForwarder::ShadowLayerForwarder(ClientLayerManager* aClientLayerManager)
+ : mClientLayerManager(aClientLayerManager)
+ , mMessageLoop(MessageLoop::current())
+ , mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC)
+ , mIsFirstPaint(false)
+ , mWindowOverlayChanged(false)
+ , mPaintSyncId(0)
+{
+ mTxn = new Transaction();
+ mActiveResourceTracker = MakeUnique<ActiveResourceTracker>(1000, "CompositableForwarder");
+}
+
+template<typename T>
+struct ReleaseOnMainThreadTask : public Runnable
+{
+ UniquePtr<T> mObj;
+
+ explicit ReleaseOnMainThreadTask(UniquePtr<T>& aObj)
+ : mObj(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);
+ mShadowManager->Destroy();
+ }
+ if (!NS_IsMainThread()) {
+ NS_DispatchToMainThread(
+ new ReleaseOnMainThreadTask<ActiveResourceTracker>(mActiveResourceTracker));
+ }
+}
+
+void
+ShadowLayerForwarder::BeginTransaction(const gfx::IntRect& aTargetBounds,
+ ScreenRotation aRotation,
+ dom::ScreenOrientationInternal aOrientation)
+{
+ MOZ_ASSERT(IPCOpen(), "no manager to forward to");
+ MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
+ UpdateFwdTransactionId();
+ mTxn->Begin(aTargetBounds, aRotation, aOrientation);
+}
+
+static PLayerChild*
+Shadow(ShadowableLayer* aLayer)
+{
+ return aLayer->GetShadow();
+}
+
+template<typename OpCreateT>
+static void
+CreatedLayer(Transaction* aTxn, ShadowableLayer* aLayer)
+{
+ aTxn->AddEdit(OpCreateT(nullptr, Shadow(aLayer)));
+}
+
+void
+ShadowLayerForwarder::CreatedPaintedLayer(ShadowableLayer* aThebes)
+{
+ CreatedLayer<OpCreatePaintedLayer>(mTxn, aThebes);
+}
+void
+ShadowLayerForwarder::CreatedContainerLayer(ShadowableLayer* aContainer)
+{
+ CreatedLayer<OpCreateContainerLayer>(mTxn, aContainer);
+}
+void
+ShadowLayerForwarder::CreatedImageLayer(ShadowableLayer* aImage)
+{
+ CreatedLayer<OpCreateImageLayer>(mTxn, aImage);
+}
+void
+ShadowLayerForwarder::CreatedColorLayer(ShadowableLayer* aColor)
+{
+ CreatedLayer<OpCreateColorLayer>(mTxn, aColor);
+}
+void
+ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas)
+{
+ CreatedLayer<OpCreateCanvasLayer>(mTxn, aCanvas);
+}
+void
+ShadowLayerForwarder::CreatedRefLayer(ShadowableLayer* aRef)
+{
+ CreatedLayer<OpCreateRefLayer>(mTxn, aRef);
+}
+
+void
+ShadowLayerForwarder::Mutated(ShadowableLayer* aMutant)
+{
+mTxn->AddMutant(aMutant);
+}
+
+void
+ShadowLayerForwarder::SetRoot(ShadowableLayer* aRoot)
+{
+ mTxn->AddEdit(OpSetRoot(nullptr, 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(nullptr, Shadow(aContainer),
+ nullptr, Shadow(aChild),
+ nullptr, Shadow(aAfter)));
+ } else {
+ mTxn->AddEdit(OpPrependChild(nullptr, Shadow(aContainer),
+ nullptr, 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(nullptr, Shadow(aContainer),
+ nullptr, 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(nullptr, Shadow(aContainer),
+ nullptr, Shadow(aChild),
+ nullptr, Shadow(aAfter)));
+ } else {
+ MOZ_LAYERS_LOG(("[LayersForwarder] OpRaiseToTopChild container=%p child=%p",
+ aContainer->AsLayer(), aChild->AsLayer()));
+ mTxn->AddEdit(OpRaiseToTopChild(nullptr, Shadow(aContainer),
+ nullptr, 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(nullptr, aCompositable->GetIPDLActor(),
+ OpUseTiledLayerBuffer(aTileLayerDescriptor)));
+}
+
+void
+ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable,
+ const ThebesBufferData& aThebesBufferData,
+ const nsIntRegion& aUpdatedRegion)
+{
+ MOZ_ASSERT(aCompositable);
+
+ if (!aCompositable->IsConnected()) {
+ return;
+ }
+
+ mTxn->AddPaint(
+ CompositableOperation(
+ nullptr, aCompositable->GetIPDLActor(),
+ OpPaintTextureRegion(aThebesBufferData, aUpdatedRegion)));
+}
+
+void
+ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures)
+{
+ MOZ_ASSERT(aCompositable);
+
+ if (!aCompositable->IsConnected()) {
+ return;
+ }
+
+ AutoTArray<TimedTexture,4> textures;
+
+ for (auto& t : aTextures) {
+ MOZ_ASSERT(t.mTextureClient);
+ MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
+ MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
+ ReadLockDescriptor readLock;
+ t.mTextureClient->SerializeReadLock(readLock);
+ textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
+ readLock,
+ t.mTimeStamp, t.mPictureRect,
+ t.mFrameID, t.mProducerID));
+ if ((t.mTextureClient->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD)
+ && t.mTextureClient->HasIntermediateBuffer()) {
+
+ // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
+ // race with updates on the main thread. In this case we want the transaction
+ // to be synchronous.
+ mTxn->MarkSyncTransaction();
+ }
+ mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
+ }
+ mTxn->AddEdit(CompositableOperation(nullptr, aCompositable->GetIPDLActor(),
+ OpUseTexture(textures)));
+}
+
+void
+ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositable,
+ TextureClient* aTextureOnBlack,
+ TextureClient* aTextureOnWhite)
+{
+ MOZ_ASSERT(aCompositable);
+
+ if (!aCompositable->IsConnected()) {
+ return;
+ }
+
+ MOZ_ASSERT(aTextureOnWhite);
+ MOZ_ASSERT(aTextureOnBlack);
+ MOZ_ASSERT(aCompositable->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnBlack->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
+ MOZ_RELEASE_ASSERT(aTextureOnWhite->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
+ MOZ_RELEASE_ASSERT(aTextureOnBlack->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
+
+ ReadLockDescriptor readLockW;
+ ReadLockDescriptor readLockB;
+ aTextureOnBlack->SerializeReadLock(readLockB);
+ aTextureOnWhite->SerializeReadLock(readLockW);
+
+ mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
+ mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
+
+ mTxn->AddEdit(
+ CompositableOperation(
+ nullptr, aCompositable->GetIPDLActor(),
+ OpUseComponentAlphaTextures(
+ nullptr, aTextureOnBlack->GetIPDLActor(),
+ nullptr, aTextureOnWhite->GetIPDLActor(),
+ readLockB, readLockW)
+ )
+ );
+}
+
+static bool
+AddOpDestroy(Transaction* aTxn, const OpDestroy& op, bool synchronously)
+{
+ if (!aTxn->Opened()) {
+ return false;
+ }
+
+ aTxn->mDestroyedActors.AppendElement(op);
+ if (synchronously) {
+ aTxn->MarkSyncTransaction();
+ }
+
+ return true;
+}
+
+bool
+ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
+{
+ return AddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
+}
+
+bool
+ShadowLayerForwarder::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
+{
+ return AddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
+}
+
+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(
+ nullptr, aCompositable->GetIPDLActor(),
+ OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
+ if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
+ mTxn->MarkSyncTransaction();
+ }
+}
+
+bool
+ShadowLayerForwarder::InWorkerThread()
+{
+ return MessageLoop::current() && (GetTextureForwarder()->GetMessageLoop()->id() == MessageLoop::current()->id());
+}
+
+void
+ShadowLayerForwarder::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>&
+ aConfigurations)
+{
+ // Cache new plugin widget configs here until we call update, at which
+ // point this data will get shipped over to chrome.
+ mPluginWindowData.Clear();
+ for (uint32_t idx = 0; idx < aConfigurations.Length(); idx++) {
+ const nsIWidget::Configuration& configuration = aConfigurations[idx];
+ mPluginWindowData.AppendElement(PluginWindowData(configuration.mWindowID,
+ configuration.mClipRegion,
+ configuration.mBounds,
+ configuration.mVisible));
+ }
+}
+
+void
+ShadowLayerForwarder::SendPaintTime(uint64_t aId, TimeDuration aPaintTime)
+{
+ if (!IPCOpen() ||
+ !mShadowManager->SendPaintTime(aId, aPaintTime)) {
+ NS_WARNING("Could not send paint times over IPC");
+ }
+}
+
+bool
+ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
+ const nsIntRegion& aRegionToClear,
+ uint64_t aId,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ const mozilla::TimeStamp& aTransactionStart,
+ bool* aSent)
+{
+ *aSent = false;
+
+ MOZ_ASSERT(IPCOpen(), "no manager to forward to");
+ if (!IPCOpen()) {
+ return false;
+ }
+
+ GetCompositorBridgeChild()->WillEndTransaction();
+
+ MOZ_ASSERT(aId);
+
+ PROFILER_LABEL("ShadowLayerForwarder", "EndTransaction",
+ js::ProfileEntry::Category::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));
+ }
+ if (mWindowOverlayChanged) {
+ mTxn->AddEdit(OpWindowOverlayChanged());
+ }
+
+ AutoTxnEnd _(mTxn);
+
+ if (mTxn->Empty() && !mTxn->RotationChanged()) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?) and no rotation event, skipping Update()"));
+ return true;
+ }
+
+ if (!mTxn->mPaints.empty()) {
+ // With some platforms, telling the drawing backend that there will be no more
+ // drawing for this frame helps with preventing command queues from spanning
+ // across multiple frames.
+ gfxPlatform::GetPlatform()->FlushContentDrawing();
+ }
+
+ MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));
+
+ MOZ_LAYERS_LOG(("[LayersForwarder] building transaction..."));
+
+ // 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 (ShadowableLayerSet::Iterator it(&mTxn->mMutants);
+ !it.Done(); it.Next()) {
+ ShadowableLayer* shadow = it.Get()->GetKey();
+
+ if (!shadow->HasShadow()) {
+ continue;
+ }
+ Layer* mutant = shadow->AsLayer();
+ MOZ_ASSERT(!!mutant, "unshadowable layer?");
+
+ LayerAttributes attrs;
+ CommonLayerAttributes& common = attrs.common();
+ common.layerBounds() = mutant->GetLayerBounds();
+ common.visibleRegion() = mutant->GetVisibleRegion();
+ common.eventRegions() = mutant->GetEventRegions();
+ common.postXScale() = mutant->GetPostXScale();
+ common.postYScale() = mutant->GetPostYScale();
+ common.transform() = mutant->GetBaseTransform();
+ common.transformIsPerspective() = mutant->GetTransformIsPerspective();
+ common.contentFlags() = mutant->GetContentFlags();
+ common.opacity() = mutant->GetOpacity();
+ common.useClipRect() = !!mutant->GetClipRect();
+ common.clipRect() = (common.useClipRect() ?
+ *mutant->GetClipRect() : ParentLayerIntRect());
+ common.scrolledClip() = mutant->GetScrolledClip();
+ common.isFixedPosition() = mutant->GetIsFixedPosition();
+ if (mutant->GetIsFixedPosition()) {
+ common.fixedPositionScrollContainerId() = mutant->GetFixedPositionScrollContainerId();
+ common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
+ common.fixedPositionSides() = mutant->GetFixedPositionSides();
+ }
+ common.isStickyPosition() = mutant->GetIsStickyPosition();
+ if (mutant->GetIsStickyPosition()) {
+ common.stickyScrollContainerId() = mutant->GetStickyScrollContainerId();
+ common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter();
+ common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner();
+ } else {
+#ifdef MOZ_VALGRIND
+ // Initialize these so that Valgrind doesn't complain when we send them
+ // to another process.
+ common.stickyScrollContainerId() = 0;
+ common.stickyScrollRangeOuter() = LayerRect();
+ common.stickyScrollRangeInner() = LayerRect();
+#endif
+ }
+ common.scrollbarTargetContainerId() = mutant->GetScrollbarTargetContainerId();
+ common.scrollbarDirection() = mutant->GetScrollbarDirection();
+ common.scrollbarThumbRatio() = mutant->GetScrollbarThumbRatio();
+ common.isScrollbarContainer() = mutant->IsScrollbarContainer();
+ common.mixBlendMode() = (int8_t)mutant->GetMixBlendMode();
+ common.forceIsolatedGroup() = mutant->GetForceIsolatedGroup();
+ if (Layer* maskLayer = mutant->GetMaskLayer()) {
+ common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
+ } else {
+ common.maskLayerChild() = nullptr;
+ }
+ common.maskLayerParent() = nullptr;
+ common.animations() = mutant->GetAnimations();
+ common.invalidRegion() = mutant->GetInvalidRegion().GetRegion();
+ common.scrollMetadata() = mutant->GetAllScrollMetadata();
+ for (size_t i = 0; i < mutant->GetAncestorMaskLayerCount(); i++) {
+ auto layer = Shadow(mutant->GetAncestorMaskLayerAt(i)->AsShadowableLayer());
+ common.ancestorMaskLayersChild().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));
+
+ mTxn->AddEdit(OpSetLayerAttributes(nullptr, Shadow(shadow), attrs));
+ }
+
+ AutoTArray<Edit, 10> cset;
+ size_t nCsets = mTxn->mCset.size() + mTxn->mPaints.size();
+ if (nCsets == 0 && !mTxn->RotationChanged()) {
+ return true;
+ }
+
+ cset.SetCapacity(nCsets);
+ if (!mTxn->mCset.empty()) {
+ cset.AppendElements(&mTxn->mCset.front(), mTxn->mCset.size());
+ }
+ // Paints after non-paint ops, including attribute changes. See
+ // above.
+ if (!mTxn->mPaints.empty()) {
+ cset.AppendElements(&mTxn->mPaints.front(), mTxn->mPaints.size());
+ }
+
+ mWindowOverlayChanged = false;
+
+ TargetConfig targetConfig(mTxn->mTargetBounds,
+ mTxn->mTargetRotation,
+ mTxn->mTargetOrientation,
+ aRegionToClear);
+
+ if (!GetTextureForwarder()->IsSameProcess()) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
+ PlatformSyncBeforeUpdate();
+ }
+
+ profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END);
+ if (mTxn->mSwapRequired) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
+ RenderTraceScope rendertrace3("Forward Transaction", "000093");
+ if (!mShadowManager->SendUpdate(cset, mTxn->mDestroyedActors,
+ GetFwdTransactionId(),
+ aId, targetConfig, mPluginWindowData,
+ mIsFirstPaint, aScheduleComposite,
+ aPaintSequenceNumber, aIsRepeatTransaction,
+ aTransactionStart, mPaintSyncId, aReplies)) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
+ return false;
+ }
+ } else {
+ // If we don't require a swap we can call SendUpdateNoSwap which
+ // assumes that aReplies is empty (DEBUG assertion)
+ MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
+ RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
+ if (!mShadowManager->SendUpdateNoSwap(cset, mTxn->mDestroyedActors,
+ GetFwdTransactionId(),
+ aId, targetConfig, mPluginWindowData,
+ mIsFirstPaint, aScheduleComposite,
+ aPaintSequenceNumber, aIsRepeatTransaction,
+ aTransactionStart, mPaintSyncId)) {
+ MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
+ return false;
+ }
+ }
+
+ *aSent = true;
+ mIsFirstPaint = false;
+ mPaintSyncId = 0;
+ MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
+ return true;
+}
+
+void
+ShadowLayerForwarder::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
+{
+ if (!IPCOpen()) {
+ return;
+ }
+ Unused << mShadowManager->SendSetLayerObserverEpoch(aLayerObserverEpoch);
+}
+
+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.
+ */
+PLayerChild*
+ShadowLayerForwarder::ConstructShadowFor(ShadowableLayer* aLayer)
+{
+ MOZ_ASSERT(IPCOpen(), "no manager to forward to");
+ if (!IPCOpen()) {
+ return nullptr;
+ }
+
+ ShadowLayerChild* child = new ShadowLayerChild();
+ if (!mShadowManager->SendPLayerConstructor(child)) {
+ return nullptr;
+ }
+
+ child->SetShadowableLayer(aLayer);
+ return child;
+}
+
+#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;
+ }
+ PCompositableChild* actor =
+ mShadowManager->SendPCompositableConstructor(aCompositable->GetTextureInfo());
+ if (!actor) {
+ return;
+ }
+ aCompositable->InitIPDLActor(actor);
+}
+
+void ShadowLayerForwarder::Attach(CompositableClient* aCompositable,
+ ShadowableLayer* aLayer)
+{
+ MOZ_ASSERT(aLayer);
+ MOZ_ASSERT(aCompositable);
+ mTxn->AddEdit(OpAttachCompositable(nullptr, Shadow(aLayer),
+ nullptr, aCompositable->GetIPDLActor()));
+}
+
+void ShadowLayerForwarder::AttachAsyncCompositable(uint64_t aCompositableID,
+ ShadowableLayer* aLayer)
+{
+ MOZ_ASSERT(aLayer);
+ MOZ_ASSERT(aCompositableID != 0); // zero is always an invalid compositable id.
+ mTxn->AddEdit(OpAttachAsyncCompositable(nullptr, Shadow(aLayer),
+ aCompositableID));
+}
+
+void ShadowLayerForwarder::SetShadowManager(PLayerTransactionChild* aShadowManager)
+{
+ mShadowManager = static_cast<LayerTransactionChild*>(aShadowManager);
+ mShadowManager->SetForwarder(this);
+}
+
+void ShadowLayerForwarder::StopReceiveAsyncParentMessge()
+{
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SetForwarder(nullptr);
+}
+
+void ShadowLayerForwarder::ClearCachedResources()
+{
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SendClearCachedResources();
+}
+
+void ShadowLayerForwarder::Composite()
+{
+ if (!IPCOpen()) {
+ return;
+ }
+ mShadowManager->SendForceComposite();
+}
+
+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<uint8_t>();
+ } else {
+ return reinterpret_cast<uint8_t*>(memOrShmem.get_uintptr_t());
+ }
+}
+
+already_AddRefed<gfx::DataSourceSurface>
+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<gfx::DrawTarget>
+GetDrawTargetForDescriptor(const SurfaceDescriptor& aDescriptor, gfx::BackendType aBackend)
+{
+ 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::CAIRO,
+ 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:
+ NS_RUNTIMEABORT("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<uintptr_t>(data);
+ } else {
+
+ mozilla::ipc::Shmem shmem;
+ if (!GetTextureForwarder()->AllocUnsafeShmem(size, OptimalShmemType(), &shmem)) {
+ return false;
+ }
+
+ bufferDesc = 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<CompositorBridgeChild*>(mShadowManager->Manager());
+ return mCompositorBridgeChild;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h
new file mode 100644
index 000000000..8b207eb1a
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -0,0 +1,465 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_ShadowLayers_h
+#define mozilla_layers_ShadowLayers_h 1
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // 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/dom/ScreenOrientation.h" // for ScreenOrientation
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/layers/CompositableForwarder.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 InfallibleTArray
+#include "nsIWidget.h"
+#include <vector>
+#include "nsExpirationTracker.h"
+
+namespace mozilla {
+namespace layers {
+
+class ClientLayerManager;
+class CompositorBridgeChild;
+class EditReply;
+class FixedSizeSmallShmemSectionAllocator;
+class ImageContainer;
+class Layer;
+class PLayerChild;
+class PLayerTransactionChild;
+class LayerTransactionChild;
+class ShadowableLayer;
+class SurfaceDescriptor;
+class TextureClient;
+class ThebesBuffer;
+class ThebesBufferData;
+class Transaction;
+
+/**
+ * See ActiveResourceTracker below.
+ */
+class ActiveResource
+{
+public:
+ virtual void NotifyInactive() = 0;
+ nsExpirationState* GetExpirationState() { return &mExpirationState; }
+ bool IsActivityTracked() { return mExpirationState.IsTracked(); }
+private:
+ nsExpirationState mExpirationState;
+};
+
+/**
+ * A convenience class on top of nsExpirationTracker
+ */
+class ActiveResourceTracker : public nsExpirationTracker<ActiveResource, 3>
+{
+public:
+ ActiveResourceTracker(uint32_t aExpirationCycle, const char* aName)
+ : nsExpirationTracker(aExpirationCycle, aName)
+ {}
+
+ virtual void NotifyExpired(ActiveResource* aResource) override
+ {
+ RemoveObject(aResource);
+ aResource->NotifyInactive();
+ }
+};
+
+/**
+ * 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(uint64_t aCompositableID,
+ ShadowableLayer* aLayer);
+
+ /**
+ * Begin recording a transaction to be forwarded atomically to a
+ * LayerManagerComposite.
+ */
+ void BeginTransaction(const gfx::IntRect& aTargetBounds,
+ ScreenRotation aRotation,
+ mozilla::dom::ScreenOrientationInternal 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 is mutated.
+ */
+ void Mutated(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;
+
+ bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
+ bool DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously) override;
+
+ virtual 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.
+ */
+ virtual void UpdateTextureRegion(CompositableClient* aCompositable,
+ const ThebesBufferData& aThebesBufferData,
+ const nsIntRegion& aUpdatedRegion) override;
+
+ /**
+ * See CompositableForwarder::UseTextures
+ */
+ virtual void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) override;
+ virtual 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(uint64_t 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(InfallibleTArray<EditReply>* aReplies,
+ const nsIntRegion& aRegionToClear,
+ uint64_t aId,
+ bool aScheduleComposite,
+ uint32_t aPaintSequenceNumber,
+ bool aIsRepeatTransaction,
+ const mozilla::TimeStamp& aTransactionStart,
+ bool* aSent);
+
+ /**
+ * Set an actor through which layer updates will be pushed.
+ */
+ void SetShadowManager(PLayerTransactionChild* aShadowManager);
+
+ /**
+ * Layout calls here to cache current plugin widget configuration
+ * data. We ship this across with the rest of the layer updates when
+ * we update. Chrome handles applying these changes.
+ */
+ void StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>&
+ aConfigurations);
+
+ void StopReceiveAsyncParentMessge();
+
+ void ClearCachedResources();
+
+ void Composite();
+
+ /**
+ * True if this is forwarding to a LayerManagerComposite.
+ */
+ bool HasShadowManager() const { return !!mShadowManager; }
+ LayerTransactionChild* GetShadowManager() const { return mShadowManager.get(); }
+
+ virtual void WindowOverlayChanged() { mWindowOverlayChanged = true; }
+
+ /**
+ * 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.
+ */
+
+ virtual bool IPCOpen() const override;
+
+ /**
+ * Construct a shadow of |aLayer| on the "other side", at the
+ * LayerManagerComposite.
+ */
+ PLayerChild* ConstructShadowFor(ShadowableLayer* aLayer);
+
+ /**
+ * Flag the next paint as the first for a document.
+ */
+ void SetIsFirstPaint() { mIsFirstPaint = true; }
+
+ void SetPaintSyncId(int32_t aSyncId) { mPaintSyncId = aSyncId; }
+
+ void SetLayerObserverEpoch(uint64_t aLayerObserverEpoch);
+
+ static void PlatformSyncBeforeUpdate();
+
+ virtual bool AllocSurfaceDescriptor(const gfx::IntSize& aSize,
+ gfxContentType aContent,
+ SurfaceDescriptor* aBuffer) override;
+
+ virtual bool AllocSurfaceDescriptorWithCaps(const gfx::IntSize& aSize,
+ gfxContentType aContent,
+ uint32_t aCaps,
+ SurfaceDescriptor* aBuffer) override;
+
+ virtual void DestroySurfaceDescriptor(SurfaceDescriptor* aSurface) override;
+
+ virtual void UpdateFwdTransactionId() override;
+ virtual uint64_t GetFwdTransactionId() override;
+
+ bool InForwarderThread() override {
+ return NS_IsMainThread();
+ }
+
+ // Returns true if aSurface wraps a Shmem.
+ static bool IsShmem(SurfaceDescriptor* aSurface);
+
+ TextureForwarder* GetTextureForwarder() override { return GetCompositorBridgeChild(); }
+ LayersIPCActor* GetLayersIPCActor() override { return this; }
+
+ ActiveResourceTracker& GetActiveResourceTracker() { return *mActiveResourceTracker.get(); }
+protected:
+ virtual ~ShadowLayerForwarder();
+
+ explicit ShadowLayerForwarder(ClientLayerManager* aClientLayerManager);
+
+#ifdef DEBUG
+ void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const;
+#else
+ void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const {}
+#endif
+
+ bool InWorkerThread();
+
+ CompositorBridgeChild* GetCompositorBridgeChild();
+
+ RefPtr<LayerTransactionChild> mShadowManager;
+ RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
+
+private:
+
+ ClientLayerManager* mClientLayerManager;
+ Transaction* mTxn;
+ MessageLoop* mMessageLoop;
+ DiagnosticTypes mDiagnosticTypes;
+ bool mIsFirstPaint;
+ bool mWindowOverlayChanged;
+ int32_t mPaintSyncId;
+ InfallibleTArray<PluginWindowData> mPluginWindowData;
+ UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
+};
+
+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; }
+
+ /**
+ * Return the IPC handle to a Shadow*Layer referring to this if one
+ * exists, nullptr if not.
+ */
+ PLayerChild* GetShadow() { return mShadow; }
+
+ virtual CompositableClient* GetCompositableClient() { return nullptr; }
+protected:
+ ShadowableLayer() : mShadow(nullptr) {}
+
+ PLayerChild* mShadow;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_ShadowLayers_h
diff --git a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
new file mode 100644
index 000000000..6a1bbcac0
--- /dev/null
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "SharedPlanarYCbCrImage.h"
+#include <stddef.h> // for size_t
+#include <stdio.h> // for printf
+#include "gfx2DGlue.h" // for Moz2D transition helpers
+#include "ISurfaceAllocator.h" // for ISurfaceAllocator, etc
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/gfx/Types.h" // for SurfaceFormat::SurfaceFormat::YUV
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/layers/ImageClient.h" // for ImageClient
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/TextureClientRecycleAllocator.h"
+#include "mozilla/layers/BufferTexture.h"
+#include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
+#include "mozilla/mozalloc.h" // for operator delete
+#include "nsISupportsImpl.h" // for Image::AddRef
+#include "mozilla/ipc/Shmem.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::ipc;
+
+SharedPlanarYCbCrImage::SharedPlanarYCbCrImage(ImageClient* aCompositable)
+: mCompositable(aCompositable)
+{
+ MOZ_COUNT_CTOR(SharedPlanarYCbCrImage);
+}
+
+SharedPlanarYCbCrImage::~SharedPlanarYCbCrImage() {
+ MOZ_COUNT_DTOR(SharedPlanarYCbCrImage);
+
+ if (mCompositable->GetAsyncID() != 0 &&
+ !InImageBridgeChildThread()) {
+ if (mTextureClient) {
+ ADDREF_MANUALLY(mTextureClient);
+ ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
+ mTextureClient = nullptr;
+ }
+ }
+}
+
+size_t
+SharedPlanarYCbCrImage::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
+{
+ // NB: Explicitly skipping mTextureClient, the memory is already reported
+ // at time of allocation in GfxMemoryImageReporter.
+ // Not owned:
+ // - mCompositable
+ return 0;
+}
+
+TextureClient*
+SharedPlanarYCbCrImage::GetTextureClient(KnowsCompositor* aForwarder)
+{
+ return mTextureClient.get();
+}
+
+uint8_t*
+SharedPlanarYCbCrImage::GetBuffer()
+{
+ // This should never be used
+ MOZ_ASSERT(false);
+ return nullptr;
+}
+
+already_AddRefed<gfx::SourceSurface>
+SharedPlanarYCbCrImage::GetAsSourceSurface()
+{
+ if (!IsValid()) {
+ NS_WARNING("Can't get as surface");
+ return nullptr;
+ }
+ return PlanarYCbCrImage::GetAsSourceSurface();
+}
+
+bool
+SharedPlanarYCbCrImage::CopyData(const PlanarYCbCrData& aData)
+{
+ // If mTextureClient has not already been allocated (through Allocate(aData))
+ // allocate it. This code path is slower than the one used when Allocate has
+ // been called since it will trigger a full copy.
+ PlanarYCbCrData data = aData;
+ if (!mTextureClient && !Allocate(data)) {
+ return false;
+ }
+
+ TextureClientAutoLock autoLock(mTextureClient, OpenMode::OPEN_WRITE_ONLY);
+ if (!autoLock.Succeeded()) {
+ MOZ_ASSERT(false, "Failed to lock the texture.");
+ return false;
+ }
+
+ if (!UpdateYCbCrTextureClient(mTextureClient, aData)) {
+ MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
+ return false;
+ }
+ mTextureClient->MarkImmutable();
+ return true;
+}
+
+// needs to be overriden because the parent class sets mBuffer which we
+// do not want to happen.
+uint8_t*
+SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
+{
+ MOZ_ASSERT(!mTextureClient, "This image already has allocated data");
+ size_t size = ImageDataSerializer::ComputeYCbCrBufferSize(aSize);
+ if (!size) {
+ return nullptr;
+ }
+
+ // XXX Add YUVColorSpace handling. Use YUVColorSpace::BT601 for now.
+ mTextureClient = TextureClient::CreateForYCbCrWithBufferSize(mCompositable->GetForwarder(),
+ size,
+ YUVColorSpace::BT601,
+ mCompositable->GetTextureFlags());
+
+ // get new buffer _without_ setting mBuffer.
+ if (!mTextureClient) {
+ return nullptr;
+ }
+
+ // update buffer size
+ mBufferSize = size;
+
+ MappedYCbCrTextureData mapped;
+ if (mTextureClient->BorrowMappedYCbCrData(mapped)) {
+ // The caller expects a pointer to the beginning of the writable part of the
+ // buffer which is where the y channel starts by default.
+ return mapped.y.data;
+ } else {
+ MOZ_CRASH("GFX: Cannot borrow mapped YCbCr data");
+ }
+}
+
+bool
+SharedPlanarYCbCrImage::AdoptData(const Data &aData)
+{
+ // AdoptData is used to update YUV plane offsets without (re)allocating
+ // memory previously allocated with AllocateAndGetNewBuffer().
+
+ MOZ_ASSERT(mTextureClient, "This Image should have already allocated data");
+ if (!mTextureClient) {
+ return false;
+ }
+ mData = aData;
+ mSize = aData.mPicSize;
+ mOrigin = gfx::IntPoint(aData.mPicX, aData.mPicY);
+
+ uint8_t *base = GetBuffer();
+ uint32_t yOffset = aData.mYChannel - base;
+ uint32_t cbOffset = aData.mCbChannel - base;
+ uint32_t crOffset = aData.mCrChannel - base;
+
+ auto fwd = mCompositable->GetForwarder();
+ bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(gfx::SurfaceFormat::YUV,
+ fwd->GetCompositorBackendType());
+
+ static_cast<BufferTextureData*>(mTextureClient->GetInternalData())->SetDesciptor(
+ YCbCrDescriptor(aData.mYSize, aData.mCbCrSize, yOffset, cbOffset, crOffset,
+ aData.mStereoMode, aData.mYUVColorSpace, hasIntermediateBuffer)
+ );
+
+ return true;
+}
+
+bool
+SharedPlanarYCbCrImage::IsValid() {
+ return mTextureClient && mTextureClient->IsValid();
+}
+
+bool
+SharedPlanarYCbCrImage::Allocate(PlanarYCbCrData& aData)
+{
+ MOZ_ASSERT(!mTextureClient,
+ "This image already has allocated data");
+ static const uint32_t MAX_POOLED_VIDEO_COUNT = 5;
+
+ if (!mCompositable->HasTextureClientRecycler()) {
+ // Initialize TextureClientRecycler
+ mCompositable->GetTextureClientRecycler()->SetMaxPoolSize(MAX_POOLED_VIDEO_COUNT);
+ }
+
+ {
+ YCbCrTextureClientAllocationHelper helper(aData, mCompositable->GetTextureFlags());
+ mTextureClient = mCompositable->GetTextureClientRecycler()->CreateOrRecycle(helper);
+ }
+
+ if (!mTextureClient) {
+ NS_WARNING("SharedPlanarYCbCrImage::Allocate failed.");
+ return false;
+ }
+
+ MappedYCbCrTextureData mapped;
+ // The locking here is sort of a lie. The SharedPlanarYCbCrImage just pulls
+ // pointers out of the TextureClient and keeps them around, which works only
+ // because the underlyin BufferTextureData is always mapped in memory even outside
+ // of the lock/unlock interval. That's sad and new code should follow this example.
+ if (!mTextureClient->Lock(OpenMode::OPEN_READ) || !mTextureClient->BorrowMappedYCbCrData(mapped)) {
+ MOZ_CRASH("GFX: Cannot lock or borrow mapped YCbCr");
+ }
+
+ aData.mYChannel = mapped.y.data;
+ aData.mCbChannel = mapped.cb.data;
+ aData.mCrChannel = mapped.cr.data;
+
+ // copy some of aData's values in mData (most of them)
+ mData.mYChannel = aData.mYChannel;
+ mData.mCbChannel = aData.mCbChannel;
+ mData.mCrChannel = aData.mCrChannel;
+ mData.mYSize = aData.mYSize;
+ mData.mCbCrSize = aData.mCbCrSize;
+ mData.mPicX = aData.mPicX;
+ mData.mPicY = aData.mPicY;
+ mData.mPicSize = aData.mPicSize;
+ mData.mStereoMode = aData.mStereoMode;
+ mData.mYUVColorSpace = aData.mYUVColorSpace;
+ // those members are not always equal to aData's, due to potentially different
+ // packing.
+ mData.mYSkip = 0;
+ mData.mCbSkip = 0;
+ mData.mCrSkip = 0;
+ mData.mYStride = mData.mYSize.width;
+ mData.mCbCrStride = mData.mCbCrSize.width;
+
+ // do not set mBuffer like in PlanarYCbCrImage because the later
+ // will try to manage this memory without knowing it belongs to a
+ // shmem.
+ mBufferSize = ImageDataSerializer::ComputeYCbCrBufferSize(mData.mYSize, mData.mCbCrSize);
+ mSize = mData.mPicSize;
+ mOrigin = gfx::IntPoint(aData.mPicX, aData.mPicY);
+
+ mTextureClient->Unlock();
+
+ return mBufferSize > 0;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/SharedPlanarYCbCrImage.h b/gfx/layers/ipc/SharedPlanarYCbCrImage.h
new file mode 100644
index 000000000..0c1b6e9c8
--- /dev/null
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 <stdint.h> // for uint8_t, uint32_t
+#include "ImageContainer.h" // for PlanarYCbCrImage, etc
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/RefPtr.h" // for RefPtr
+#include "mozilla/ipc/Shmem.h" // for Shmem
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsDebug.h" // for NS_WARNING
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR
+
+#ifndef MOZILLA_LAYERS_SHAREDPLANARYCBCRIMAGE_H
+#define MOZILLA_LAYERS_SHAREDPLANARYCBCRIMAGE_H
+
+namespace mozilla {
+namespace layers {
+
+class ImageClient;
+class TextureClient;
+
+class SharedPlanarYCbCrImage : public PlanarYCbCrImage
+{
+public:
+ explicit SharedPlanarYCbCrImage(ImageClient* aCompositable);
+
+protected:
+ ~SharedPlanarYCbCrImage();
+
+public:
+ virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
+ virtual uint8_t* GetBuffer() override;
+
+ virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
+ virtual bool CopyData(const PlanarYCbCrData& aData) override;
+ virtual bool AdoptData(const Data &aData) override;
+
+ virtual bool Allocate(PlanarYCbCrData& aData);
+ virtual uint8_t* AllocateAndGetNewBuffer(uint32_t aSize) override;
+
+ virtual bool IsValid() override;
+
+ virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
+ {
+ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+ }
+
+ virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
+
+private:
+ RefPtr<TextureClient> mTextureClient;
+ RefPtr<ImageClient> mCompositable;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/SharedRGBImage.cpp b/gfx/layers/ipc/SharedRGBImage.cpp
new file mode 100644
index 000000000..bb3bb968c
--- /dev/null
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -0,0 +1,113 @@
+/* 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 "SharedRGBImage.h"
+#include "ImageTypes.h" // for ImageFormat::SHARED_RGB, etc
+#include "Shmem.h" // for Shmem
+#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat, etc
+#include "gfxPlatform.h" // for gfxPlatform, gfxImageFormat
+#include "mozilla/gfx/Point.h" // for IntSIze
+#include "mozilla/layers/BufferTexture.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator, etc
+#include "mozilla/layers/ImageClient.h" // for ImageClient
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/TextureClient.h" // for BufferTextureClient, etc
+#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
+#include "nsISupportsImpl.h" // for Image::AddRef, etc
+#include "nsRect.h" // for mozilla::gfx::IntRect
+
+// Just big enough for a 1080p RGBA32 frame
+#define MAX_FRAME_SIZE (16 * 1024 * 1024)
+
+namespace mozilla {
+namespace layers {
+
+already_AddRefed<Image>
+CreateSharedRGBImage(ImageContainer *aImageContainer,
+ gfx::IntSize aSize,
+ gfxImageFormat aImageFormat)
+{
+ NS_ASSERTION(aImageFormat == gfx::SurfaceFormat::A8R8G8B8_UINT32 ||
+ aImageFormat == gfx::SurfaceFormat::X8R8G8B8_UINT32 ||
+ aImageFormat == gfx::SurfaceFormat::R5G6B5_UINT16,
+ "RGB formats supported only");
+
+ if (!aImageContainer) {
+ NS_WARNING("No ImageContainer to allocate SharedRGBImage");
+ return nullptr;
+ }
+
+ RefPtr<SharedRGBImage> rgbImage = aImageContainer->CreateSharedRGBImage();
+ if (!rgbImage) {
+ NS_WARNING("Failed to create SharedRGBImage");
+ return nullptr;
+ }
+ if (!rgbImage->Allocate(aSize, gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
+ NS_WARNING("Failed to allocate a shared image");
+ return nullptr;
+ }
+ return rgbImage.forget();
+}
+
+SharedRGBImage::SharedRGBImage(ImageClient* aCompositable)
+: Image(nullptr, ImageFormat::SHARED_RGB)
+, mCompositable(aCompositable)
+{
+ MOZ_COUNT_CTOR(SharedRGBImage);
+}
+
+SharedRGBImage::~SharedRGBImage()
+{
+ MOZ_COUNT_DTOR(SharedRGBImage);
+
+ if (mCompositable->GetAsyncID() != 0 &&
+ !InImageBridgeChildThread()) {
+ ADDREF_MANUALLY(mTextureClient);
+ ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient);
+ mTextureClient = nullptr;
+ }
+}
+
+bool
+SharedRGBImage::Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
+{
+ mSize = aSize;
+ mTextureClient = mCompositable->CreateBufferTextureClient(aFormat, aSize,
+ gfx::BackendType::NONE,
+ TextureFlags::DEFAULT);
+ return !!mTextureClient;
+}
+
+uint8_t*
+SharedRGBImage::GetBuffer()
+{
+ MappedTextureData mapped;
+ if (mTextureClient && mTextureClient->BorrowMappedData(mapped)) {
+ return mapped.data;
+ }
+ return 0;
+}
+
+gfx::IntSize
+SharedRGBImage::GetSize()
+{
+ return mSize;
+}
+
+TextureClient*
+SharedRGBImage::GetTextureClient(KnowsCompositor* aForwarder)
+{
+ return mTextureClient.get();
+}
+
+already_AddRefed<gfx::SourceSurface>
+SharedRGBImage::GetAsSourceSurface()
+{
+ return nullptr;
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/SharedRGBImage.h b/gfx/layers/ipc/SharedRGBImage.h
new file mode 100644
index 000000000..2c6009c19
--- /dev/null
+++ b/gfx/layers/ipc/SharedRGBImage.h
@@ -0,0 +1,59 @@
+/* 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 SHAREDRGBIMAGE_H_
+#define SHAREDRGBIMAGE_H_
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint8_t
+#include "ImageContainer.h" // for ISharedImage, Image, etc
+#include "gfxTypes.h"
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/RefPtr.h" // for RefPtr
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/gfx/Types.h" // for SurfaceFormat
+#include "nsCOMPtr.h" // for already_AddRefed
+
+namespace mozilla {
+namespace layers {
+
+class ImageClient;
+class TextureClient;
+
+already_AddRefed<Image> CreateSharedRGBImage(ImageContainer* aImageContainer,
+ gfx::IntSize aSize,
+ gfxImageFormat aImageFormat);
+
+/**
+ * Stores RGB data in shared memory
+ * It is assumed that the image width and stride are equal
+ */
+class SharedRGBImage : public Image
+{
+public:
+ explicit SharedRGBImage(ImageClient* aCompositable);
+
+protected:
+ ~SharedRGBImage();
+
+public:
+ virtual TextureClient* GetTextureClient(KnowsCompositor* aForwarder) override;
+
+ virtual uint8_t* GetBuffer() override;
+
+ gfx::IntSize GetSize() override;
+
+ already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
+
+ bool Allocate(gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
+private:
+ gfx::IntSize mSize;
+ RefPtr<ImageClient> mCompositable;
+ RefPtr<TextureClient> mTextureClient;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/SynchronousTask.h b/gfx/layers/ipc/SynchronousTask.h
new file mode 100644
index 000000000..fc20e2843
--- /dev/null
+++ b/gfx/layers/ipc/SynchronousTask.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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_GFX_SYNCHRONOUSTASK_H
+#define MOZILLA_GFX_SYNCHRONOUSTASK_H
+
+#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
+
+namespace mozilla {
+namespace layers {
+
+// Helper that creates a monitor and a "done" flag, then enters the monitor.
+// This can go away when we switch ImageBridge to an XPCOM thread.
+class MOZ_STACK_CLASS SynchronousTask
+{
+ friend class AutoCompleteTask;
+
+public:
+ explicit SynchronousTask(const char* name)
+ : mMonitor(name),
+ mAutoEnter(mMonitor),
+ mDone(false)
+ {}
+
+ void Wait() {
+ while (!mDone) {
+ mMonitor.Wait();
+ }
+ }
+
+private:
+ void Complete() {
+ mDone = true;
+ mMonitor.NotifyAll();
+ }
+
+private:
+ ReentrantMonitor mMonitor;
+ ReentrantMonitorAutoEnter mAutoEnter;
+ bool mDone;
+};
+
+class MOZ_STACK_CLASS AutoCompleteTask
+{
+public:
+ explicit AutoCompleteTask(SynchronousTask* aTask)
+ : mTask(aTask),
+ mAutoEnter(aTask->mMonitor)
+ {
+ }
+ ~AutoCompleteTask() {
+ mTask->Complete();
+ }
+
+private:
+ SynchronousTask* mTask;
+ ReentrantMonitorAutoEnter mAutoEnter;
+};
+
+}
+}
+
+#endif
diff --git a/gfx/layers/ipc/TextureForwarder.h b/gfx/layers/ipc/TextureForwarder.h
new file mode 100644
index 000000000..0d06fa5f5
--- /dev/null
+++ b/gfx/layers/ipc/TextureForwarder.h
@@ -0,0 +1,79 @@
+/* -*- 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_TEXTUREFORWARDER
+#define MOZILLA_LAYERS_TEXTUREFORWARDER
+
+#include <stdint.h> // for int32_t, uint64_t
+#include "gfxTypes.h"
+#include "mozilla/layers/LayersTypes.h" // for LayersBackend
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/layers/KnowsCompositor.h"
+
+namespace mozilla {
+namespace ipc {
+class IShmemAllocator;
+}
+namespace layers {
+
+/**
+ * An abstract interface for classes that implement the autogenerated
+ * IPDL actor class. Lets us check if they are still valid for IPC.
+ */
+class LayersIPCActor {
+public:
+ virtual bool IPCOpen() const { return true; }
+};
+
+/**
+ * An abstract interface for LayersIPCActors that implement a top-level
+ * IPDL protocol so also have their own channel.
+ * Has their own MessageLoop for message dispatch, and can allocate
+ * shmem.
+ */
+class LayersIPCChannel : public LayersIPCActor
+ , public mozilla::ipc::IShmemAllocator {
+public:
+ NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
+ NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
+
+ virtual bool IsSameProcess() const = 0;
+
+ virtual bool UsesImageBridge() const { return false; }
+
+ virtual base::ProcessId GetParentPid() const = 0;
+
+ virtual MessageLoop* GetMessageLoop() const = 0;
+
+ virtual FixedSizeSmallShmemSectionAllocator* GetTileLockAllocator() { return nullptr; }
+
+ virtual void CancelWaitForRecycle(uint64_t aTextureId) = 0;
+
+protected:
+ virtual ~LayersIPCChannel() {}
+};
+
+/**
+ * An abstract interface for classes that can allocate PTexture objects
+ * across IPDL. Currently a sub-class of LayersIPCChannel for simplicity
+ * since all our implementations use both, but could be independant if needed.
+ */
+class TextureForwarder : public LayersIPCChannel {
+public:
+ /**
+ * Create a TextureChild/Parent pair as as well as the TextureHost on the parent side.
+ */
+ virtual PTextureChild* CreateTexture(
+ const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial) = 0;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
new file mode 100644
index 000000000..e64705478
--- /dev/null
+++ b/gfx/layers/ipc/ThreadSafeRefcountingWithMainThreadDestruction.h
@@ -0,0 +1,91 @@
+/* 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 THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
+#define THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
+
+#include "base/message_loop.h"
+#include "MainThreadUtils.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace layers {
+
+inline MessageLoop* GetMainLoopAssertingMainThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return MessageLoop::current();
+}
+
+inline MessageLoop* GetMainLoop()
+{
+ static MessageLoop* sMainLoop = GetMainLoopAssertingMainThread();
+ return sMainLoop;
+}
+
+struct HelperForMainThreadDestruction
+{
+ HelperForMainThreadDestruction()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ GetMainLoop();
+ }
+
+ ~HelperForMainThreadDestruction()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ }
+};
+
+template<typename T>
+struct DeleteOnMainThreadTask : public Runnable
+{
+ T* mToDelete;
+ explicit DeleteOnMainThreadTask(T* aToDelete) : mToDelete(aToDelete) {}
+ NS_IMETHOD Run() override {
+ MOZ_ASSERT(NS_IsMainThread());
+ mToDelete->DeleteToBeCalledOnMainThread();
+ return NS_OK;
+ }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \
+public: \
+ NS_METHOD_(MozExternalRefCountType) AddRef(void) { \
+ MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
+ MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
+ nsrefcnt count = ++mRefCnt; \
+ NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
+ return (nsrefcnt) count; \
+ } \
+ void DeleteToBeCalledOnMainThread() { \
+ MOZ_ASSERT(NS_IsMainThread()); \
+ NS_LOG_RELEASE(this, 0, #_class); \
+ delete this; \
+ } \
+ NS_METHOD_(MozExternalRefCountType) Release(void) { \
+ MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
+ nsrefcnt count = --mRefCnt; \
+ if (count == 0) { \
+ if (NS_IsMainThread()) { \
+ DeleteToBeCalledOnMainThread(); \
+ } else { \
+ NS_DispatchToMainThread( \
+ new mozilla::layers::DeleteOnMainThreadTask<_class>(this)); \
+ } \
+ } else { \
+ NS_LOG_RELEASE(this, count, #_class); \
+ } \
+ return count; \
+ } \
+protected: \
+ ::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
+private: \
+ ::mozilla::layers::HelperForMainThreadDestruction mHelperForMainThreadDestruction; \
+public:
+
+#endif
diff --git a/gfx/layers/ipc/VideoBridgeChild.cpp b/gfx/layers/ipc/VideoBridgeChild.cpp
new file mode 100644
index 000000000..9651c563e
--- /dev/null
+++ b/gfx/layers/ipc/VideoBridgeChild.cpp
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "VideoBridgeChild.h"
+#include "VideoBridgeParent.h"
+#include "CompositorThread.h"
+
+namespace mozilla {
+namespace layers {
+
+StaticRefPtr<VideoBridgeChild> sVideoBridgeChildSingleton;
+
+/* static */ void
+VideoBridgeChild::Startup()
+{
+ sVideoBridgeChildSingleton = new VideoBridgeChild();
+ RefPtr<VideoBridgeParent> parent = new VideoBridgeParent();
+
+ MessageLoop* loop = CompositorThreadHolder::Loop();
+
+ sVideoBridgeChildSingleton->Open(parent->GetIPCChannel(),
+ loop,
+ ipc::ChildSide);
+ sVideoBridgeChildSingleton->mIPDLSelfRef = sVideoBridgeChildSingleton;
+ parent->SetOtherProcessId(base::GetCurrentProcId());
+}
+
+/* static */ void
+VideoBridgeChild::Shutdown()
+{
+ if (sVideoBridgeChildSingleton) {
+ sVideoBridgeChildSingleton->Close();
+ sVideoBridgeChildSingleton = nullptr;
+ }
+}
+
+VideoBridgeChild::VideoBridgeChild()
+ : mMessageLoop(MessageLoop::current())
+ , mCanSend(true)
+{
+}
+
+VideoBridgeChild::~VideoBridgeChild()
+{
+}
+
+VideoBridgeChild*
+VideoBridgeChild::GetSingleton()
+{
+ return sVideoBridgeChildSingleton;
+}
+
+bool
+VideoBridgeChild::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PVideoBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+bool
+VideoBridgeChild::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ MOZ_ASSERT(CanSend());
+ return PVideoBridgeChild::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+VideoBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
+{
+ return PVideoBridgeChild::DeallocShmem(aShmem);
+}
+
+PTextureChild*
+VideoBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+ const LayersBackend&,
+ const TextureFlags&,
+ const uint64_t& aSerial)
+{
+ MOZ_ASSERT(CanSend());
+ return TextureClient::CreateIPDLActor();
+}
+
+bool
+VideoBridgeChild::DeallocPTextureChild(PTextureChild* actor)
+{
+ return TextureClient::DestroyIPDLActor(actor);
+}
+
+void
+VideoBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+ mCanSend = false;
+}
+
+void
+VideoBridgeChild::DeallocPVideoBridgeChild()
+{
+ mIPDLSelfRef = nullptr;
+}
+
+PTextureChild*
+VideoBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial)
+{
+ MOZ_ASSERT(CanSend());
+ return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+bool VideoBridgeChild::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/VideoBridgeChild.h b/gfx/layers/ipc/VideoBridgeChild.h
new file mode 100644
index 000000000..f5677008e
--- /dev/null
+++ b/gfx/layers/ipc/VideoBridgeChild.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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_GFX_VIDEOBRIDGECHILD_H
+#define MOZILLA_GFX_VIDEOBRIDGECHILD_H
+
+#include "mozilla/layers/PVideoBridgeChild.h"
+#include "ISurfaceAllocator.h"
+#include "TextureForwarder.h"
+
+namespace mozilla {
+namespace layers {
+
+class VideoBridgeChild final : public PVideoBridgeChild
+ , public TextureForwarder
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoBridgeChild, override);
+
+ static void Startup();
+ static void Shutdown();
+
+ static VideoBridgeChild* GetSingleton();
+
+ // PVideoBridgeChild
+ PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial) override;
+ bool DeallocPTextureChild(PTextureChild* actor) override;
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+ void DeallocPVideoBridgeChild() override;
+
+
+ // ISurfaceAllocator
+ bool AllocUnsafeShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) override;
+ bool AllocShmem(size_t aSize,
+ mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
+ mozilla::ipc::Shmem* aShmem) override;
+ bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
+ // TextureForwarder
+ PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial) override;
+
+ // ClientIPCAllocator
+ base::ProcessId GetParentPid() const override { return OtherPid(); }
+ MessageLoop * GetMessageLoop() const override { return mMessageLoop; }
+ void CancelWaitForRecycle(uint64_t aTextureId) override { MOZ_ASSERT(false, "NO RECYCLING HERE"); }
+
+ // ISurfaceAllocator
+ bool IsSameProcess() const override;
+
+ bool CanSend() { return mCanSend; }
+
+private:
+ VideoBridgeChild();
+ ~VideoBridgeChild();
+
+ RefPtr<VideoBridgeChild> mIPDLSelfRef;
+ MessageLoop* mMessageLoop;
+ bool mCanSend;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/ipc/VideoBridgeParent.cpp b/gfx/layers/ipc/VideoBridgeParent.cpp
new file mode 100644
index 000000000..fce2184c8
--- /dev/null
+++ b/gfx/layers/ipc/VideoBridgeParent.cpp
@@ -0,0 +1,125 @@
+/* vim: set ts=2 sw=2 et tw=80: */
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "VideoBridgeParent.h"
+#include "mozilla/layers/TextureHost.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::ipc;
+using namespace mozilla::gfx;
+using namespace mozilla::media;
+
+
+static VideoBridgeParent* sVideoBridgeSingleton;
+
+VideoBridgeParent::VideoBridgeParent()
+ : mClosed(false)
+{
+ mSelfRef = this;
+ sVideoBridgeSingleton = this;
+}
+
+VideoBridgeParent::~VideoBridgeParent()
+{
+ sVideoBridgeSingleton = nullptr;
+}
+
+/* static */ VideoBridgeParent*
+VideoBridgeParent::GetSingleton()
+{
+ return sVideoBridgeSingleton;
+}
+
+TextureHost*
+VideoBridgeParent::LookupTexture(uint64_t aSerial)
+{
+ return TextureHost::AsTextureHost(mTextureMap[aSerial]);
+}
+
+void
+VideoBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ // Can't alloc/dealloc shmems from now on.
+ mClosed = true;
+}
+
+void
+VideoBridgeParent::DeallocPVideoBridgeParent()
+{
+ mSelfRef = nullptr;
+}
+
+PTextureParent*
+VideoBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial)
+{
+ PTextureParent* parent =
+ TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
+ mTextureMap[aSerial] = parent;
+ return parent;
+}
+
+bool
+VideoBridgeParent::DeallocPTextureParent(PTextureParent* actor)
+{
+ mTextureMap.erase(TextureHost::GetTextureSerial(actor));
+ return TextureHost::DestroyIPDLActor(actor);
+}
+
+void
+VideoBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
+{
+ MOZ_ASSERT(false, "AsyncMessages not supported");
+}
+
+bool
+VideoBridgeParent::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (mClosed) {
+ return false;
+ }
+ return PVideoBridgeParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+VideoBridgeParent::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (mClosed) {
+ return false;
+ }
+ return PVideoBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+void
+VideoBridgeParent::DeallocShmem(ipc::Shmem& aShmem)
+{
+ if (mClosed) {
+ return;
+ }
+ PVideoBridgeParent::DeallocShmem(aShmem);
+}
+
+bool
+VideoBridgeParent::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void
+VideoBridgeParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
+{
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/ipc/VideoBridgeParent.h b/gfx/layers/ipc/VideoBridgeParent.h
new file mode 100644
index 000000000..e5560acab
--- /dev/null
+++ b/gfx/layers/ipc/VideoBridgeParent.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 gfx_layers_ipc_VideoBridgeParent_h_
+#define gfx_layers_ipc_VideoBridgeParent_h_
+
+#include "mozilla/layers/PVideoBridgeParent.h"
+
+namespace mozilla {
+namespace layers {
+
+class VideoBridgeParent final : public PVideoBridgeParent,
+ public HostIPCAllocator,
+ public ShmemAllocator
+{
+public:
+ VideoBridgeParent();
+ ~VideoBridgeParent();
+
+ static VideoBridgeParent* GetSingleton();
+ TextureHost* LookupTexture(uint64_t aSerial);
+
+ // PVideoBridgeParent
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+ PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial) override;
+ bool DeallocPTextureParent(PTextureParent* actor) override;
+
+ // HostIPCAllocator
+ base::ProcessId GetChildProcessId() override
+ {
+ return OtherPid();
+ }
+ void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
+ void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
+
+ // ISurfaceAllocator
+ ShmemAllocator* AsShmemAllocator() override { return this; }
+ bool IsSameProcess() const override;
+ bool IPCOpen() const override { return !mClosed; }
+
+ // ShmemAllocator
+ 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;
+
+ void DeallocShmem(ipc::Shmem& aShmem) override;
+
+private:
+ void DeallocPVideoBridgeParent() override;
+
+ // This keeps us alive until ActorDestroy(), at which point we do a
+ // deferred destruction of ourselves.
+ RefPtr<VideoBridgeParent> mSelfRef;
+
+ std::map<uint64_t, PTextureParent*> mTextureMap;
+
+ bool mClosed;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // gfx_layers_ipc_VideoBridgeParent_h_