Bug 1341064. Send child side built display lists over gecko ipc to compositor.
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 01 Mar 2017 20:36:27 -0500
changeset 345794 6422bc2ab9747390455a1b8a63f34c8965282ff9
parent 345793 9503f5f64ba0a99e38f6cb16df350805f770945d
child 345795 8744594fc366cf463313d3636e62789a907b0877
push id31446
push userkwierso@gmail.com
push dateFri, 03 Mar 2017 19:24:21 +0000
treeherdermozilla-central@942165e408f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1341064
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1341064. Send child side built display lists over gecko ipc to compositor.
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/layers/wr/WebRenderMessageUtils.h
gfx/webrender_bindings/WebRenderTypes.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -13,16 +13,18 @@ include "mozilla/layers/WebRenderMessage
 include WebRenderMessages;
 include protocol PCompositorBridge;
 include protocol PTexture;
 
 using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
 using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
+using WrBuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
+using WrAuxiliaryListsDescriptor from "mozilla/webrender/webrender_ffi.h";
 
 namespace mozilla {
 namespace layers {
 
 sync protocol PWebRenderBridge
 {
   manager PCompositorBridge;
 
@@ -33,18 +35,20 @@ parent:
   sync Create(IntSize aSize);
   sync AddImage(ImageKey aImageKey, IntSize aSize, uint32_t aStride,
                 SurfaceFormat aFormat, ByteBuffer aBytes);
   sync UpdateImage(ImageKey aImageKey, IntSize aSize,
                    SurfaceFormat aFormat, ByteBuffer aBytes);
   sync DeleteImage(ImageKey aImageKey);
   async AddRawFont(FontKey aFontKey, ByteBuffer aBytes, uint32_t aFontIndex);
   async DPBegin(IntSize aSize);
-  async DPEnd(IntSize aSize, WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
-  sync DPSyncEnd(IntSize aSize, WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId);
+  async DPEnd(IntSize aSize, WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
+              ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
+  sync DPSyncEnd(IntSize aSize, WebRenderCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
+                 ByteBuffer aDL, WrBuiltDisplayListDescriptor aDLDesc, ByteBuffer aAux, WrAuxiliaryListsDescriptor aAuxDesc);
   sync DPGetSnapshot(PTexture texture);
   async AddExternalImageId(uint64_t aImageId, CompositableHandle aHandle);
   async AddExternalImageIdForCompositable(uint64_t aImageId, CompositableHandle aHandle);
   async RemoveExternalImageId(uint64_t aImageId);
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
   async ClearCachedResources();
 
   async Shutdown();
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -6,24 +6,26 @@
 
 #include "mozilla/layers/WebRenderBridgeChild.h"
 
 #include "gfxPlatform.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/PTextureChild.h"
+#include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
   : mIsInTransaction(false)
   , mIdNamespace(0)
   , mResourceId(0)
+  , mPipelineId(aPipelineId)
   , mIPCOpen(false)
   , mDestroyed(false)
 {
 }
 
 void
 WebRenderBridgeChild::Destroy()
 {
@@ -64,25 +66,146 @@ WebRenderBridgeChild::DPBegin(const gfx:
   MOZ_ASSERT(!mIsInTransaction);
 
   UpdateFwdTransactionId();
   this->SendDPBegin(aSize);
   mIsInTransaction = true;
   return true;
 }
 
+wr::BuiltDisplayList
+WebRenderBridgeChild::ProcessWebrenderCommands(const gfx::IntSize &aSize,
+                                               InfallibleTArray<WebRenderCommand>& aCommands)
+{
+  wr::DisplayListBuilder builder(mPipelineId);
+  builder.Begin(ViewAs<LayerPixel>(aSize));
+
+  for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
+    const WebRenderCommand& cmd = aCommands[i];
+
+    switch (cmd.type()) {
+      case WebRenderCommand::TOpDPPushStackingContext: {
+        const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
+        builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPopStackingContext: {
+        builder.PopStackingContext();
+        break;
+      }
+      case WebRenderCommand::TOpDPPushScrollLayer: {
+        const OpDPPushScrollLayer& op = cmd.get_OpDPPushScrollLayer();
+        builder.PushScrollLayer(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr));
+        break;
+      }
+      case WebRenderCommand::TOpDPPopScrollLayer: {
+        builder.PopScrollLayer();
+        break;
+      }
+      case WebRenderCommand::TOpDPPushRect: {
+        const OpDPPushRect& op = cmd.get_OpDPPushRect();
+        builder.PushRect(op.bounds(), op.clip(), op.color());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushBorder: {
+        const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
+        builder.PushBorder(op.bounds(), op.clip(),
+                           op.top(), op.right(), op.bottom(), op.left(),
+                           op.radius());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushLinearGradient: {
+        const OpDPPushLinearGradient& op = cmd.get_OpDPPushLinearGradient();
+        builder.PushLinearGradient(op.bounds(), op.clip(),
+                                   op.startPoint(), op.endPoint(),
+                                   op.stops(), op.extendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushRadialGradient: {
+        const OpDPPushRadialGradient& op = cmd.get_OpDPPushRadialGradient();
+        builder.PushRadialGradient(op.bounds(), op.clip(),
+                                   op.startCenter(), op.endCenter(),
+                                   op.startRadius(), op.endRadius(),
+                                   op.stops(), op.extendMode());
+        break;
+      }
+      case WebRenderCommand::TOpDPPushImage: {
+        const OpDPPushImage& op = cmd.get_OpDPPushImage();
+        builder.PushImage(op.bounds(), op.clip(),
+                          op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
+        break;
+      }
+      case WebRenderCommand::TOpAddExternalImage: {
+        // done on the parent
+        break;
+      }
+      case WebRenderCommand::TOpDPPushIframe: {
+        const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
+        builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
+        break;
+      }
+      case WebRenderCommand::TCompositableOperation: {
+        // done on the parent
+        break;
+      }
+      case WebRenderCommand::TOpDPPushText: {
+        const OpDPPushText& op = cmd.get_OpDPPushText();
+        const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
+
+        for (size_t i = 0; i < glyph_array.Length(); i++) {
+          const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
+          builder.PushText(op.bounds(),
+                           op.clip(),
+                           glyph_array[i].color,
+                           op.key(),
+                           Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
+                           op.glyph_size());
+        }
+
+        break;
+      }
+      case WebRenderCommand::TOpDPPushBoxShadow: {
+        const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
+        builder.PushBoxShadow(op.rect(),
+                              op.clip(),
+                              op.box_bounds(),
+                              op.offset(),
+                              op.color(),
+                              op.blur_radius(),
+                              op.spread_radius(),
+                              op.border_radius(),
+                              op.clip_mode());
+        break;
+      }
+      default:
+        NS_RUNTIMEABORT("not reached");
+    }
+  }
+  builder.End();
+  wr::BuiltDisplayList dl;
+  builder.Finalize(dl.dl_desc, dl.dl, dl.aux_desc, dl.aux);
+  return dl;
+}
+
 void
 WebRenderBridgeChild::DPEnd(const gfx::IntSize& aSize, bool aIsSync, uint64_t aTransactionId)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(mIsInTransaction);
+
+  wr::BuiltDisplayList dl = ProcessWebrenderCommands(aSize, mCommands);
+  ByteBuffer dlData(Move(dl.dl));
+  ByteBuffer auxData(Move(dl.aux));
+
   if (aIsSync) {
-    this->SendDPSyncEnd(aSize, mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
+    this->SendDPSyncEnd(aSize, mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
+                        dlData, dl.dl_desc, auxData, dl.aux_desc);
   } else {
-    this->SendDPEnd(aSize, mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
+    this->SendDPEnd(aSize, mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId,
+                    dlData, dl.dl_desc, auxData, dl.aux_desc);
   }
 
   mCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
 }
 
 uint64_t
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -63,16 +63,19 @@ public:
 
 private:
   friend class CompositorBridgeChild;
 
   ~WebRenderBridgeChild() {}
 
   uint64_t GetNextExternalImageId();
 
+  wr::BuiltDisplayList ProcessWebrenderCommands(const gfx::IntSize &aSize,
+                                                InfallibleTArray<WebRenderCommand>& aCommands);
+
   // CompositableForwarder
   void Connect(CompositableClient* aCompositable,
                ImageContainer* aImageContainer = nullptr) override;
   void UseTiledLayerBuffer(CompositableClient* aCompositable,
                            const SurfaceDescriptorTiles& aTiledDescriptor) override;
   void UpdateTextureRegion(CompositableClient* aCompositable,
                            const ThebesBufferData& aThebesBufferData,
                            const nsIntRegion& aUpdatedRegion) override;
@@ -106,16 +109,17 @@ private:
   bool AddOpDestroy(const OpDestroy& aOp);
 
   nsTArray<WebRenderCommand> mCommands;
   nsTArray<OpDestroy> mDestroyedActors;
   nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
   bool mIsInTransaction;
   uint32_t mIdNamespace;
   uint32_t mResourceId;
+  wr::PipelineId mPipelineId;
 
   bool mIPCOpen;
   bool mDestroyed;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -16,16 +16,21 @@
 #include "mozilla/layers/CompositorVsyncScheduler.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/WebRenderCompositableHolder.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/widget/CompositorWidget.h"
 
+bool is_in_main_thread()
+{
+  return NS_IsMainThread();
+}
+
 bool is_in_compositor_thread()
 {
   return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
 }
 
 bool is_in_render_thread()
 {
   return mozilla::wr::RenderThread::IsInRenderThread();
@@ -81,17 +86,16 @@ WebRenderBridgeParent::WebRenderBridgePa
                                              const wr::PipelineId& aPipelineId,
                                              widget::CompositorWidget* aWidget,
                                              CompositorVsyncScheduler* aScheduler,
                                              RefPtr<wr::WebRenderAPI>&& aApi,
                                              RefPtr<WebRenderCompositableHolder>&& aHolder)
   : mCompositorBridge(aCompositorBridge)
   , mPipelineId(aPipelineId)
   , mWidget(aWidget)
-  , mBuilder(Nothing())
   , mApi(aApi)
   , mCompositableHolder(aHolder)
   , mCompositorScheduler(aScheduler)
   , mChildLayerObserverEpoch(0)
   , mParentLayerObserverEpoch(0)
   , mWrEpoch(0)
   , mIdNameSpace(++sIdNameSpace)
   , mDestroyed(false)
@@ -106,21 +110,17 @@ WebRenderBridgeParent::WebRenderBridgePa
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
 
-  if (mBuilder.isSome()) {
-    return IPC_OK();
-  }
   MOZ_ASSERT(mApi);
-  mBuilder.emplace(mPipelineId);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvShutdown()
 {
   if (mDestroyed) {
@@ -134,17 +134,16 @@ WebRenderBridgeParent::RecvShutdown()
 }
 
 void
 WebRenderBridgeParent::Destroy()
 {
   if (mDestroyed) {
     return;
   }
-  MOZ_ASSERT(mBuilder.isSome());
   mDestroyed = true;
   ClearResources();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvAddImage(const wr::ImageKey& aImageKey,
 				    const gfx::IntSize& aSize,
                                     const uint32_t& aStride,
@@ -207,131 +206,95 @@ WebRenderBridgeParent::RecvDeleteImage(c
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPBegin(const gfx::IntSize& aSize)
 {
   if (mDestroyed) {
     return IPC_OK();
   }
-  MOZ_ASSERT(mBuilder.isSome());
-  mBuilder.ref().Begin(LayerIntSize(aSize.width, aSize.height));
   return IPC_OK();
 }
 
 void
 WebRenderBridgeParent::HandleDPEnd(const gfx::IntSize& aSize,
                                  InfallibleTArray<WebRenderCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
-                                 const uint64_t& aTransactionId)
+                                 const uint64_t& aTransactionId,
+                                 const ByteBuffer& dl,
+                                 const WrBuiltDisplayListDescriptor& dlDesc,
+                                 const ByteBuffer& aux,
+                                 const WrAuxiliaryListsDescriptor& auxDesc)
 {
   UpdateFwdTransactionId(aFwdTransactionId);
 
   if (mDestroyed) {
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
     return;
   }
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvDPEnd without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
   ++mWrEpoch; // Update webrender epoch
-  ProcessWebrenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch));
+  ProcessWebrenderCommands(aSize, aCommands, wr::NewEpoch(mWrEpoch),
+                           dl, dlDesc, aux, auxDesc);
   HoldPendingTransactionId(mWrEpoch, aTransactionId);
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPEnd(const gfx::IntSize& aSize,
                                  InfallibleTArray<WebRenderCommand>&& aCommands,
                                  InfallibleTArray<OpDestroy>&& aToDestroy,
                                  const uint64_t& aFwdTransactionId,
-                                 const uint64_t& aTransactionId)
+                                 const uint64_t& aTransactionId,
+                                 const ByteBuffer& dl,
+                                 const WrBuiltDisplayListDescriptor& dlDesc,
+                                 const ByteBuffer& aux,
+                                 const WrAuxiliaryListsDescriptor& auxDesc)
 {
-  HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
+  HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
+              dl, dlDesc, aux, auxDesc);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvDPSyncEnd(const gfx::IntSize &aSize,
                                      InfallibleTArray<WebRenderCommand>&& aCommands,
                                      InfallibleTArray<OpDestroy>&& aToDestroy,
                                      const uint64_t& aFwdTransactionId,
-                                     const uint64_t& aTransactionId)
+                                     const uint64_t& aTransactionId,
+                                     const ByteBuffer& dl,
+                                     const WrBuiltDisplayListDescriptor& dlDesc,
+                                     const ByteBuffer& aux,
+                                     const WrAuxiliaryListsDescriptor& auxDesc)
 {
-  HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId);
+  HandleDPEnd(aSize, Move(aCommands), Move(aToDestroy), aFwdTransactionId, aTransactionId,
+              dl, dlDesc, aux, auxDesc);
   return IPC_OK();
 }
 
 void
 WebRenderBridgeParent::ProcessWebrenderCommands(const gfx::IntSize &aSize,
-                                                InfallibleTArray<WebRenderCommand>& aCommands, const wr::Epoch& aEpoch)
+                                                InfallibleTArray<WebRenderCommand>& aCommands, const wr::Epoch& aEpoch,
+                                                const ByteBuffer& dl,
+                                                const WrBuiltDisplayListDescriptor& dlDesc,
+                                                const ByteBuffer& aux,
+                                                const WrAuxiliaryListsDescriptor& auxDesc)
 {
-  MOZ_ASSERT(mBuilder.isSome());
-  wr::DisplayListBuilder& builder = mBuilder.ref();
   // XXX remove it when external image key is used.
   std::vector<wr::ImageKey> keysToDelete;
 
   for (InfallibleTArray<WebRenderCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
     const WebRenderCommand& cmd = aCommands[i];
 
     switch (cmd.type()) {
-      case WebRenderCommand::TOpDPPushStackingContext: {
-        const OpDPPushStackingContext& op = cmd.get_OpDPPushStackingContext();
-        builder.PushStackingContext(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr), op.opacity(), op.matrix(), op.mixBlendMode());
-        break;
-      }
-      case WebRenderCommand::TOpDPPopStackingContext: {
-        builder.PopStackingContext();
-        break;
-      }
-      case WebRenderCommand::TOpDPPushScrollLayer: {
-        const OpDPPushScrollLayer& op = cmd.get_OpDPPushScrollLayer();
-        builder.PushScrollLayer(op.bounds(), op.overflow(), op.mask().ptrOr(nullptr));
-        break;
-      }
-      case WebRenderCommand::TOpDPPopScrollLayer: {
-        builder.PopScrollLayer();
-        break;
-      }
-      case WebRenderCommand::TOpDPPushRect: {
-        const OpDPPushRect& op = cmd.get_OpDPPushRect();
-        builder.PushRect(op.bounds(), op.clip(), op.color());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushBorder: {
-        const OpDPPushBorder& op = cmd.get_OpDPPushBorder();
-        builder.PushBorder(op.bounds(), op.clip(),
-                           op.top(), op.right(), op.bottom(), op.left(),
-                           op.radius());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushLinearGradient: {
-        const OpDPPushLinearGradient& op = cmd.get_OpDPPushLinearGradient();
-        builder.PushLinearGradient(op.bounds(), op.clip(),
-                                   op.startPoint(), op.endPoint(),
-                                   op.stops(), op.extendMode());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushRadialGradient: {
-        const OpDPPushRadialGradient& op = cmd.get_OpDPPushRadialGradient();
-        builder.PushRadialGradient(op.bounds(), op.clip(),
-                                   op.startCenter(), op.endCenter(),
-                                   op.startRadius(), op.endRadius(),
-                                   op.stops(), op.extendMode());
-        break;
-      }
-      case WebRenderCommand::TOpDPPushImage: {
-        const OpDPPushImage& op = cmd.get_OpDPPushImage();
-        builder.PushImage(op.bounds(), op.clip(),
-                          op.mask().ptrOr(nullptr), op.filter(), wr::ImageKey(op.key()));
-        break;
-      }
       case WebRenderCommand::TOpAddExternalImage: {
         const OpAddExternalImage& op = cmd.get_OpAddExternalImage();
         MOZ_ASSERT(mExternalImageIds.Get(op.externalImageId()).get());
 
         RefPtr<CompositableHost> host = mExternalImageIds.Get(op.externalImageId());
         if (!host) {
           break;
         }
@@ -354,70 +317,32 @@ WebRenderBridgeParent::ProcessWebrenderC
         keysToDelete.push_back(key);
         dSurf->Unmap();
         // XXX workaround for releasing Readlock. See Bug 1339625
         if(host->GetType() == CompositableType::CONTENT_SINGLE) {
           host->CleanupResources();
         }
         break;
       }
-      case WebRenderCommand::TOpDPPushIframe: {
-        const OpDPPushIframe& op = cmd.get_OpDPPushIframe();
-        builder.PushIFrame(op.bounds(), op.clip(), op.pipelineId());
-        break;
-      }
       case WebRenderCommand::TCompositableOperation: {
         if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
           NS_ERROR("ReceiveCompositableUpdate failed");
         }
         break;
       }
-      case WebRenderCommand::TOpDPPushText: {
-        const OpDPPushText& op = cmd.get_OpDPPushText();
-        const nsTArray<WrGlyphArray>& glyph_array = op.glyph_array();
-
-        for (size_t i = 0; i < glyph_array.Length(); i++) {
-          const nsTArray<WrGlyphInstance>& glyphs = glyph_array[i].glyphs;
-          builder.PushText(op.bounds(),
-                           op.clip(),
-                           glyph_array[i].color,
-                           op.key(),
-                           Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
-                           op.glyph_size());
-        }
-
+      default: {
+        // other commands are handle on the child
         break;
       }
-      case WebRenderCommand::TOpDPPushBoxShadow: {
-        const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
-        builder.PushBoxShadow(op.rect(),
-                              op.clip(),
-                              op.box_bounds(),
-                              op.offset(),
-                              op.color(),
-                              op.blur_radius(),
-                              op.spread_radius(),
-                              op.border_radius(),
-                              op.clip_mode());
-        break;
-      }
-      default:
-        NS_RUNTIMEABORT("not reached");
     }
   }
-  builder.End();
-  WrBuiltDisplayListDescriptor dlDesc;
-  wr::VecU8 dlData;
-  WrAuxiliaryListsDescriptor auxDesc;
-  wr::VecU8 auxData;
-  builder.Finalize(dlDesc, dlData, auxDesc, auxData);
   mApi->SetRootDisplayList(gfx::Color(0.3f, 0.f, 0.f, 1.f), aEpoch, LayerSize(aSize.width, aSize.height),
                            mPipelineId,
-                           dlDesc, dlData.inner.data, dlData.inner.length,
-                           auxDesc, auxData.inner.data, auxData.inner.length);
+                           dlDesc, dl.mData, dl.mLength,
+                           auxDesc, aux.mData, aux.mLength);
 
   ScheduleComposition();
   DeleteOldImages();
 
   // XXX remove it when external image key is used.
   if (!keysToDelete.empty()) {
     mKeysToDelete.swap(keysToDelete);
   }
@@ -465,17 +390,16 @@ WebRenderBridgeParent::RecvDPGetSnapshot
   // Assert the stride of the buffer is what webrender expects
   MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
 
   if (mCompositorScheduler->NeedsComposite()) {
     mCompositorScheduler->CancelCurrentCompositeTask();
     mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr);
   }
 
-  MOZ_ASSERT(mBuilder.isSome());
   mApi->Readback(size, buffer, buffer_size);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvAddExternalImageId(const uint64_t& aImageId,
                                               const CompositableHandle& aHandle)
@@ -650,19 +574,16 @@ WebRenderBridgeParent::ClearResources()
   if (mCompositableHolder) {
     for (auto iter = mExternalImageIds.Iter(); !iter.Done(); iter.Next()) {
       uint64_t externalImageId = iter.Key();
       mCompositableHolder->RemoveExternalImageId(externalImageId);
     }
   }
   mExternalImageIds.Clear();
 
-  if (mBuilder.isSome()) {
-    mBuilder.reset();
-  }
   if (mWidget && mCompositorScheduler) {
     mCompositorScheduler->Destroy();
   }
   mCompositorScheduler = nullptr;
   mApi = nullptr;
   mCompositorBridge = nullptr;
 }
 
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -74,22 +74,30 @@ public:
                                           const gfx::SurfaceFormat& aFormat,
                                           const ByteBuffer& aBuffer) override;
   mozilla::ipc::IPCResult RecvDeleteImage(const wr::ImageKey& a1) override;
   mozilla::ipc::IPCResult RecvDPBegin(const gfx::IntSize& aSize) override;
   mozilla::ipc::IPCResult RecvDPEnd(const gfx::IntSize& aSize,
                                     InfallibleTArray<WebRenderCommand>&& aCommands,
                                     InfallibleTArray<OpDestroy>&& aToDestroy,
                                     const uint64_t& aFwdTransactionId,
-                                    const uint64_t& aTransactionId) override;
+                                    const uint64_t& aTransactionId,
+                                    const ByteBuffer& dl,
+                                    const WrBuiltDisplayListDescriptor& dlDesc,
+                                    const ByteBuffer& aux,
+                                    const WrAuxiliaryListsDescriptor& auxDesc) override;
   mozilla::ipc::IPCResult RecvDPSyncEnd(const gfx::IntSize& aSize,
                                         InfallibleTArray<WebRenderCommand>&& aCommands,
                                         InfallibleTArray<OpDestroy>&& aToDestroy,
                                         const uint64_t& aFwdTransactionId,
-                                        const uint64_t& aTransactionId) override;
+                                        const uint64_t& aTransactionId,
+                                        const ByteBuffer& dl,
+                                        const WrBuiltDisplayListDescriptor& dlDesc,
+                                        const ByteBuffer& aux,
+                                        const WrAuxiliaryListsDescriptor& auxDesc) override;
   mozilla::ipc::IPCResult RecvDPGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvAddExternalImageId(const uint64_t& aImageId,
                                                  const CompositableHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvAddExternalImageIdForCompositable(const uint64_t& aImageId,
                                                                 const CompositableHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvRemoveExternalImageId(const uint64_t& aImageId) override;
   mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
@@ -137,41 +145,48 @@ public:
   {
     return mIdNameSpace;
   }
 
 private:
   virtual ~WebRenderBridgeParent();
 
   void DeleteOldImages();
-  void ProcessWebrenderCommands(const gfx::IntSize &aSize, InfallibleTArray<WebRenderCommand>& commands, const wr::Epoch& aEpoch);
+  void ProcessWebrenderCommands(const gfx::IntSize &aSize, InfallibleTArray<WebRenderCommand>& commands, const wr::Epoch& aEpoch,
+                                    const ByteBuffer& dl,
+                                    const WrBuiltDisplayListDescriptor& dlDesc,
+                                    const ByteBuffer& aux,
+                                    const WrAuxiliaryListsDescriptor& auxDesc);
   void ScheduleComposition();
   void ClearResources();
   uint64_t GetChildLayerObserverEpoch() const { return mChildLayerObserverEpoch; }
   bool ShouldParentObserveEpoch();
   void HandleDPEnd(const gfx::IntSize& aSize,
                    InfallibleTArray<WebRenderCommand>&& aCommands,
                    InfallibleTArray<OpDestroy>&& aToDestroy,
                    const uint64_t& aFwdTransactionId,
-                   const uint64_t& aTransactionId);
+                   const uint64_t& aTransactionId,
+                   const ByteBuffer& dl,
+                   const WrBuiltDisplayListDescriptor& dlDesc,
+                   const ByteBuffer& aux,
+                   const WrAuxiliaryListsDescriptor& auxDesc);
 
 private:
   struct PendingTransactionId {
     PendingTransactionId(wr::Epoch aEpoch, uint64_t aId)
       : mEpoch(aEpoch)
       , mId(aId)
     {}
     wr::Epoch mEpoch;
     uint64_t mId;
   };
 
   CompositorBridgeParentBase* MOZ_NON_OWNING_REF mCompositorBridge;
   wr::PipelineId mPipelineId;
   RefPtr<widget::CompositorWidget> mWidget;
-  Maybe<wr::DisplayListBuilder> mBuilder;
   RefPtr<wr::WebRenderAPI> mApi;
   RefPtr<WebRenderCompositableHolder> mCompositableHolder;
   RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
   std::vector<wr::ImageKey> mKeysToDelete;
   nsDataHashtable<nsUint64HashKey, RefPtr<CompositableHost>> mExternalImageIds;
   nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
 
   // These fields keep track of the latest layer observer epoch values in the child and the
--- a/gfx/layers/wr/WebRenderMessageUtils.h
+++ b/gfx/layers/wr/WebRenderMessageUtils.h
@@ -323,16 +323,55 @@ struct ParamTraits<WrImageMask>
   {
     return ReadParam(aMsg, aIter, &aResult->image)
         && ReadParam(aMsg, aIter, &aResult->rect)
         && ReadParam(aMsg, aIter, &aResult->repeat);
   }
 };
 
 template<>
+struct ParamTraits<WrBuiltDisplayListDescriptor>
+{
+  static void
+  Write(Message* aMsg, const WrBuiltDisplayListDescriptor& aParam)
+  {
+    WriteParam(aMsg, aParam.display_list_items_size);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrBuiltDisplayListDescriptor* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->display_list_items_size);
+  }
+};
+
+template<>
+struct ParamTraits<WrAuxiliaryListsDescriptor>
+{
+  static void
+  Write(Message* aMsg, const WrAuxiliaryListsDescriptor& aParam)
+  {
+    WriteParam(aMsg, aParam.gradient_stops_size);
+    WriteParam(aMsg, aParam.complex_clip_regions_size);
+    WriteParam(aMsg, aParam.filters_size);
+    WriteParam(aMsg, aParam.glyph_instances_size);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrAuxiliaryListsDescriptor* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->gradient_stops_size)
+        && ReadParam(aMsg, aIter, &aResult->complex_clip_regions_size)
+        && ReadParam(aMsg, aIter, &aResult->filters_size)
+        && ReadParam(aMsg, aIter, &aResult->glyph_instances_size);
+  }
+};
+
+
+template<>
 struct ParamTraits<WrImageRendering>
   : public ContiguousEnumSerializer<
         WrImageRendering,
         WrImageRendering::Auto,
         WrImageRendering::Sentinel>
 {
 };
 
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -240,24 +240,61 @@ static inline WrPoint ToWrPoint(const gf
 
 static inline WrExternalImageId ToWrExternalImageId(uint64_t aID)
 {
   WrExternalImageId id;
   id.id = aID;
   return id;
 }
 
+struct VecU8 {
+  WrVecU8 inner;
+  VecU8() {
+    inner.data = nullptr;
+    inner.capacity = 0;
+  }
+  VecU8(VecU8&) = delete;
+  VecU8(VecU8&& src) {
+    inner = src.inner;
+    src.inner.data = nullptr;
+    src.inner.capacity = 0;
+  }
+
+  ~VecU8() {
+    if (inner.data) {
+      wr_vec_u8_free(inner);
+    }
+  }
+};
+
 struct ByteBuffer
 {
   ByteBuffer(size_t aLength, uint8_t* aData)
     : mLength(aLength)
     , mData(aData)
     , mOwned(false)
   {}
 
+  // XXX: this is a bit of hack that assumes
+  // the allocators are the same
+  explicit ByteBuffer(VecU8&& vec)
+  {
+    if (vec.inner.capacity) {
+      mLength = vec.inner.length;
+      mData = vec.inner.data;
+      vec.inner.data = nullptr;
+      vec.inner.capacity = 0;
+      mOwned = true;
+    } else {
+      mOwned = false;
+      mData = nullptr;
+      mLength = 0;
+    }
+  }
+
   ByteBuffer()
     : mLength(0)
     , mData(nullptr)
     , mOwned(false)
   {}
 
   bool
   Allocate(size_t aLength)
@@ -288,29 +325,19 @@ struct ByteBuffer
           !(memcmp(mData, other.mData, mLength));
   }
 
   size_t mLength;
   uint8_t* mData;
   bool mOwned;
 };
 
-struct VecU8 {
-  WrVecU8 inner;
-  VecU8() {
-    inner.data = nullptr;
-  }
-  VecU8(VecU8&) = delete;
-  VecU8(VecU8&& src) {
-    inner = src.inner;
-    src.inner.data = nullptr;
-  }
-
-  ~VecU8() {
-    if (inner.data)
-      wr_vec_u8_free(inner);
-  }
+struct BuiltDisplayList {
+  VecU8 dl;
+  WrBuiltDisplayListDescriptor dl_desc;
+  VecU8 aux;
+  WrAuxiliaryListsDescriptor aux_desc;
 };
 
 } // namespace wr
 } // namespace mozilla
 
 #endif /* GFX_WEBRENDERTYPES_H */
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -120,16 +120,17 @@ fn get_proc_address(glcontext_ptr: *mut 
     }
 
     symbol as *const _
 }
 
 extern  {
     fn is_in_compositor_thread() -> bool;
     fn is_in_render_thread() -> bool;
+    fn is_in_main_thread() -> bool;
 }
 
 #[no_mangle]
 pub extern fn wr_renderer_update(renderer: &mut Renderer) {
     renderer.update();
 }
 
 #[no_mangle]
@@ -309,39 +310,39 @@ pub extern fn wr_window_new(window_id: W
     *out_api = Box::into_raw(Box::new(sender.create_api()));
     *out_renderer = Box::into_raw(Box::new(renderer));
 
     return true;
 }
 
 #[no_mangle]
 pub extern fn wr_state_new(pipeline_id: PipelineId) -> *mut WrState {
-    assert!(unsafe { is_in_compositor_thread() });
+    assert!(unsafe { is_in_main_thread() });
 
     let state = Box::new(WrState {
         pipeline_id: pipeline_id,
         z_index: 0,
         frame_builder: WebRenderFrameBuilder::new(pipeline_id),
     });
 
     Box::into_raw(state)
 }
 
 #[no_mangle]
 pub extern fn wr_state_delete(state:*mut WrState) {
-    assert!(unsafe { is_in_compositor_thread() });
+    assert!(unsafe { is_in_main_thread() });
 
     unsafe {
         Box::from_raw(state);
     }
 }
 
 #[no_mangle]
 pub extern fn wr_dp_begin(state: &mut WrState, width: u32, height: u32) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.list.clear();
     state.z_index = 0;
 
     let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(width as f32, height as f32));
 
     state.frame_builder.dl_builder.push_stacking_context(
         webrender_traits::ScrollPolicy::Scrollable,
         bounds,
@@ -351,17 +352,17 @@ pub extern fn wr_dp_begin(state: &mut Wr
         LayoutTransform::identity(),
         webrender_traits::MixBlendMode::Normal,
         Vec::new(),
     );
 }
 
 #[no_mangle]
 pub extern fn wr_dp_end(state: &mut WrState) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_stacking_context();
 }
 
 #[no_mangle]
 pub unsafe extern fn wr_renderer_flush_rendered_epochs(renderer: &mut Renderer) -> *mut Vec<(PipelineId, Epoch)> {
     let map = renderer.flush_rendered_epochs();
     let pipeline_epochs = Box::new(map.into_iter().collect());
     return Box::into_raw(pipeline_epochs);
@@ -596,17 +597,17 @@ impl WrGradientExtendMode
             WrGradientExtendMode::Repeat => ExtendMode::Repeat,
         }
     }
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_stacking_context(state:&mut WrState, bounds: WrRect, overflow: WrRect, mask: *const WrImageMask, opacity: f32, transform: &LayoutTransform, mix_blend_mode: WrMixBlendMode)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.z_index += 1;
 
     let bounds = bounds.to_rect();
     let mut overflow = overflow.to_rect();
     let mix_blend_mode = mix_blend_mode.to_mix_blend_mode();
     //println!("stacking context: {:?} {:?} {:?} {:?} {:?}", state.pipeline_id, bounds, overflow, mask, transform);
     // convert from the C type to the Rust type
     let mask = unsafe { mask.as_ref().map(|&WrImageMask{image, ref rect,repeat}| ImageMask{image: image, rect: rect.to_rect(), repeat: repeat}) };
@@ -629,17 +630,17 @@ pub extern fn wr_dp_push_stacking_contex
                                   filters);
     state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, ServoScrollRootId(1));
 
 }
 
 #[no_mangle]
 pub extern fn wr_dp_pop_stacking_context(state: &mut WrState)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
     state.frame_builder.dl_builder.pop_stacking_context();
     //println!("pop_stacking {:?}", state.pipeline_id);
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_scroll_layer(state: &mut WrState, bounds: WrRect, overflow: WrRect, mask: Option<&WrImageMask>)
 {
@@ -648,17 +649,17 @@ pub extern fn wr_dp_push_scroll_layer(st
     let mask = mask.map(|&WrImageMask{image, ref rect,repeat}| ImageMask{image: image, rect: rect.to_rect(), repeat: repeat});
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], mask);
     state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, ServoScrollRootId(1));
 }
 
 #[no_mangle]
 pub extern fn wr_dp_pop_scroll_layer(state: &mut WrState)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
 }
 
 #[no_mangle]
 pub extern fn wr_api_set_root_pipeline(api: &mut RenderApi, pipeline_id: PipelineId) {
     api.set_root_pipeline(pipeline_id);
     api.generate_frame(None);
 }
@@ -723,48 +724,48 @@ pub extern fn wr_api_send_external_event
     assert!(unsafe { is_in_compositor_thread() });
 
     api.send_external_event(ExternalEvent::from_raw(evt));
 }
 
 
 #[no_mangle]
 pub extern fn wr_dp_push_rect(state: &mut WrState, rect: WrRect, clip: WrRect, color: WrColor) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
 
     state.frame_builder.dl_builder.push_rect(
                                     rect.to_rect(),
                                     clip_region,
                                     color.to_color());
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrRect,
                                     box_bounds: WrRect, offset: WrPoint, color: WrColor,
                                     blur_radius: f32, spread_radius: f32, border_radius: f32,
                                     clip_mode: WrBoxShadowClipMode) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
     state.frame_builder.dl_builder.push_box_shadow(rect.to_rect(),
                                                    clip_region,
                                                    box_bounds.to_rect(),
                                                    offset.to_point(),
                                                    color.to_color(),
                                                    blur_radius,
                                                    spread_radius,
                                                    border_radius,
                                                    clip_mode.to_box_shadow_clip_mode());
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_border(state: &mut WrState, rect: WrRect, clip: WrRect,
                                 top: WrBorderSide, right: WrBorderSide, bottom: WrBorderSide, left: WrBorderSide,
                                 radius: WrBorderRadius) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
     let border_widths = BorderWidths {
         left: left.width,
         top: top.width,
         right: right.width,
         bottom: bottom.width
     };
     let border_details = BorderDetails::Normal(NormalBorder {
@@ -781,17 +782,17 @@ pub extern fn wr_dp_push_border(state: &
                                     border_details);
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_linear_gradient(state: &mut WrState, rect: WrRect, clip: WrRect,
                                          start_point: WrPoint, end_point: WrPoint,
                                          stops: * const WrGradientStop, stops_count: usize,
                                          extend_mode: WrGradientExtendMode) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let stops = WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
 
     state.frame_builder.dl_builder.push_gradient(
                                     rect.to_rect(),
                                     clip_region,
                                     start_point.to_point(),
@@ -802,17 +803,17 @@ pub extern fn wr_dp_push_linear_gradient
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_radial_gradient(state: &mut WrState, rect: WrRect, clip: WrRect,
                                          start_center: WrPoint, end_center: WrPoint,
                                          start_radius: f32, end_radius: f32,
                                          stops: * const WrGradientStop, stops_count: usize,
                                          extend_mode: WrGradientExtendMode) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let stops = WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
 
     state.frame_builder.dl_builder.push_radial_gradient(
                                     rect.to_rect(),
                                     clip_region,
                                     start_center.to_point(),
@@ -821,17 +822,17 @@ pub extern fn wr_dp_push_radial_gradient
                                     end_radius,
                                     stops,
                                     extend_mode.to_gradient_extend_mode()
                                     );
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_iframe(state: &mut WrState, rect: WrRect, clip: WrRect, pipeline_id: PipelineId) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(),
                                                                      Vec::new(),
                                                                      None);
     state.frame_builder.dl_builder.push_iframe(rect.to_rect(),
                                                clip_region,
                                                pipeline_id);
 }
@@ -971,17 +972,17 @@ impl WrImageMask
     pub fn to_image_mask(&self) -> ImageMask
     {
         ImageMask { image: self.image, rect: self.rect.to_rect(), repeat: self.repeat }
     }
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_image(state:&mut WrState, bounds: WrRect, clip : WrRect, mask: *const WrImageMask, filter: ImageRendering, key: ImageKey) {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let bounds = bounds.to_rect();
     let clip = clip.to_rect();
 
     //println!("push_image bounds {:?} clip {:?}", bounds, clip);
     // convert from the C type to the Rust type, mapping NULL to None
     let mask = unsafe { mask.as_ref().map(|m| m.to_image_mask()) };
     let image_rendering = filter;
@@ -1025,17 +1026,17 @@ pub extern fn wr_dp_push_text(state: &mu
                               bounds: WrRect,
                               clip: WrRect,
                               color: WrColor,
                               font_key: FontKey,
                               glyphs: *mut GlyphInstance,
                               glyph_count: u32,
                               glyph_size: f32)
 {
-    assert!( unsafe { is_in_compositor_thread() });
+    assert!( unsafe { is_in_main_thread() });
 
     let glyph_slice = unsafe {
         slice::from_raw_parts(glyphs, glyph_count as usize)
     };
     let mut glyph_vector = Vec::new();
     glyph_vector.extend_from_slice(&glyph_slice);
 
     let colorf = ColorF::new(color.r, color.g, color.b, color.a);
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -59,16 +59,17 @@ WR_DECL_FFI_2(WrFontKey, uint32_t, uint3
 #undef WR_DECL_FFI_1
 #undef WR_DECL_FFI_2
 
 // ----
 // Functions invoked from Rust code
 // ----
 
 bool is_in_compositor_thread();
+bool is_in_main_thread();
 bool is_in_render_thread();
 void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
 
 // -----
 // Enums used in C++ code with corresponding enums in Rust code
 // -----
 enum class WrBoxShadowClipMode: uint32_t {
   None,