merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Mon, 01 May 2017 11:21:49 +0200
changeset 355835 076a7a66096f9e8d102548397254be32eb26bc3d
parent 355820 de63010ad9d6877979587327e4b63038a561dfc5 (current diff)
parent 355834 084bebaffd26e5a0e3aa71b0751b95bce6ac356f (diff)
child 355836 11dffbfd31f50a7daaa142892be1c0c2542db1aa
child 355849 83113056a17715711e8544248bd82ce30cbd4da2
child 355882 42f89cd146543b14914138b21642197bc0290854
push id31745
push userarchaeopteryx@coole-files.de
push dateMon, 01 May 2017 09:22:05 +0000
treeherdermozilla-central@076a7a66096f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone55.0a1
first release with
nightly linux32
076a7a66096f / 55.0a1 / 20170501100240 / files
nightly linux64
076a7a66096f / 55.0a1 / 20170501100238 / files
nightly mac
076a7a66096f / 55.0a1 / 20170501030204 / files
nightly win32
076a7a66096f / 55.0a1 / 20170501030204 / files
nightly win64
076a7a66096f / 55.0a1 / 20170501030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: 4QFAkv28IPJ
dom/base/nsFocusManager.cpp
tools/profiler/core/ProfilerMarkers.cpp
tools/profiler/public/ProfilerMarkers.h
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1053,18 +1053,19 @@ nsFocusManager::FireDelayedEvents(nsIDoc
         mDelayedBlurFocusEvents.RemoveElementAt(i);
         --i;
       } else if (!aDocument->EventHandlingSuppressed()) {
         EventMessage message = mDelayedBlurFocusEvents[i].mEventMessage;
         nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
         nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
         nsCOMPtr<EventTarget> relatedTarget = mDelayedBlurFocusEvents[i].mRelatedTarget;
         mDelayedBlurFocusEvents.RemoveElementAt(i);
-        SendFocusOrBlurEvent(message, presShell, aDocument, target, 0,
-                             false, false, relatedTarget);
+
+        FireFocusOrBlurEvent(message, presShell, target, false, false,
+                             relatedTarget);
         --i;
       }
     }
   }
 
   return NS_OK;
 }
 
@@ -2076,25 +2077,25 @@ GetDocumentHelper(EventTarget* aTarget)
   if (!node) {
     nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aTarget);
     return win ? win->GetExtantDoc() : nullptr;
   }
 
   return node->OwnerDoc();
 }
 
-void nsFocusManager::SendFocusInOrOutEvent(EventMessage aEventMessage,
+void nsFocusManager::FireFocusInOrOutEvent(EventMessage aEventMessage,
                                      nsIPresShell* aPresShell,
                                      nsISupports* aTarget,
                                      nsPIDOMWindowOuter* aCurrentFocusedWindow,
                                      nsIContent* aCurrentFocusedContent,
                                      EventTarget* aRelatedTarget)
 {
   NS_ASSERTION(aEventMessage == eFocusIn || aEventMessage == eFocusOut,
-      "Wrong event type for SendFocusInOrOutEvent");
+      "Wrong event type for FireFocusInOrOutEvent");
 
   nsContentUtils::AddScriptRunner(
       new FocusInOutEvent(
         aTarget,
         aEventMessage,
         aPresShell->GetPresContext(),
         aCurrentFocusedWindow,
         aCurrentFocusedContent,
@@ -2112,21 +2113,16 @@ nsFocusManager::SendFocusOrBlurEvent(Eve
                                      EventTarget* aRelatedTarget)
 {
   NS_ASSERTION(aEventMessage == eFocus || aEventMessage == eBlur,
                "Wrong event type for SendFocusOrBlurEvent");
 
   nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
   nsCOMPtr<nsIDocument> eventTargetDoc = GetDocumentHelper(eventTarget);
   nsCOMPtr<nsIDocument> relatedTargetDoc = GetDocumentHelper(aRelatedTarget);
-  nsCOMPtr<nsPIDOMWindowOuter> currentWindow = mFocusedWindow;
-  nsCOMPtr<nsPIDOMWindowInner> targetWindow = do_QueryInterface(aTarget);
-  nsCOMPtr<nsIDocument> targetDocument = do_QueryInterface(aTarget);
-  nsCOMPtr<nsIContent> currentFocusedContent = currentWindow ?
-      currentWindow->GetFocusedNode() : nullptr;
 
   // set aRelatedTarget to null if it's not in the same document as eventTarget
   if (eventTargetDoc != relatedTargetDoc) {
     aRelatedTarget = nullptr;
   }
 
   bool dontDispatchEvent =
     eventTargetDoc && nsContentUtils::IsUserFocusIgnored(eventTargetDoc);
@@ -2144,16 +2140,46 @@ nsFocusManager::SendFocusOrBlurEvent(Eve
     }
 
     mDelayedBlurFocusEvents.AppendElement(
       nsDelayedBlurOrFocusEvent(aEventMessage, aPresShell,
                                 aDocument, eventTarget, aRelatedTarget));
     return;
   }
 
+  // If mDelayedBlurFocusEvents queue is not empty, check if there are events
+  // that belongs to this doc, if yes, fire them first.
+  if (aDocument && !aDocument->EventHandlingSuppressed() &&
+      mDelayedBlurFocusEvents.Length()) {
+    FireDelayedEvents(aDocument);
+  }
+
+  FireFocusOrBlurEvent(aEventMessage, aPresShell, aTarget, aWindowRaised,
+                       aIsRefocus, aRelatedTarget);
+}
+
+void
+nsFocusManager::FireFocusOrBlurEvent(EventMessage aEventMessage,
+                                     nsIPresShell* aPresShell,
+                                     nsISupports* aTarget,
+                                     bool aWindowRaised,
+                                     bool aIsRefocus,
+                                     EventTarget* aRelatedTarget)
+{
+  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
+  nsCOMPtr<nsIDocument> eventTargetDoc = GetDocumentHelper(eventTarget);
+  nsCOMPtr<nsPIDOMWindowOuter> currentWindow = mFocusedWindow;
+  nsCOMPtr<nsPIDOMWindowInner> targetWindow = do_QueryInterface(aTarget);
+  nsCOMPtr<nsIDocument> targetDocument = do_QueryInterface(aTarget);
+  nsCOMPtr<nsIContent> currentFocusedContent = currentWindow ?
+      currentWindow->GetFocusedNode() : nullptr;
+
+  bool dontDispatchEvent =
+    eventTargetDoc && nsContentUtils::IsUserFocusIgnored(eventTargetDoc);
+
 #ifdef ACCESSIBILITY
   nsAccessibilityService* accService = GetAccService();
   if (accService) {
     if (aEventMessage == eFocus) {
       accService->NotifyOfDOMFocus(aTarget);
     } else {
       accService->NotifyOfDOMBlur(aTarget);
     }
@@ -2169,17 +2195,17 @@ nsFocusManager::SendFocusOrBlurEvent(Eve
     // focusin/focusout. Other browsers do not fire focusin/focusout on window,
     // despite being required in the spec, so follow their behavior.
     //
     // As for document, we should not even fire focus/blur, but until then, we
     // need this check. targetDocument should be removed once bug 1228802 is
     // resolved.
     if (!targetWindow && !targetDocument) {
       EventMessage focusInOrOutMessage = aEventMessage == eFocus ? eFocusIn : eFocusOut;
-      SendFocusInOrOutEvent(focusInOrOutMessage, aPresShell, aTarget,
+      FireFocusInOrOutEvent(focusInOrOutMessage, aPresShell, aTarget,
           currentWindow, currentFocusedContent, aRelatedTarget);
     }
   }
 }
 
 void
 nsFocusManager::ScrollIntoView(nsIPresShell* aPresShell,
                                nsIContent* aContent,
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -275,50 +275,66 @@ protected:
              uint32_t aFlags,
              bool aIsNewDocument,
              bool aFocusChanged,
              bool aWindowRaised,
              bool aAdjustWidget,
              nsIContent* aContentLostFocus = nullptr);
 
   /**
-   * Fires a focus or blur event at aTarget.
+   * Send a focus or blur event at aTarget. It may be added to the delayed
+   * event queue if the document is suppressing events.
    *
    * aEventMessage should be either eFocus or eBlur.
    * For blur events, aFocusMethod should normally be non-zero.
    *
    * aWindowRaised should only be true if called from WindowRaised.
    */
   void SendFocusOrBlurEvent(mozilla::EventMessage aEventMessage,
                             nsIPresShell* aPresShell,
                             nsIDocument* aDocument,
                             nsISupports* aTarget,
                             uint32_t aFocusMethod,
                             bool aWindowRaised,
                             bool aIsRefocus = false,
                             mozilla::dom::EventTarget* aRelatedTarget = nullptr);
 
   /**
-   *  Send a focusin or focusout event
+   * Fire a focus or blur event at aTarget.
+   *
+   * aEventMessage should be either eFocus or eBlur.
+   * For blur events, aFocusMethod should normally be non-zero.
+   *
+   * aWindowRaised should only be true if called from WindowRaised.
+   */
+  void FireFocusOrBlurEvent(mozilla::EventMessage aEventMessage,
+                            nsIPresShell* aPresShell,
+                            nsISupports* aTarget,
+                            bool aWindowRaised,
+                            bool aIsRefocus = false,
+                            mozilla::dom::EventTarget* aRelatedTarget = nullptr);
+
+  /**
+   *  Fire a focusin or focusout event
    *
    *  aEventMessage should be either eFocusIn or eFocusOut.
    *
    *  aTarget is the content the event will fire on (the object that gained
    *  focus for focusin, the object blurred for focusout).
    *
    *  aCurrentFocusedWindow is the window focused before the focus/blur event
    *  was fired.
    *
    *  aCurrentFocusedContent is the content focused before the focus/blur event
    *  was fired.
    *
    *  aRelatedTarget is the content related to the event (the object
    *  losing focus for focusin, the object getting focus for focusout).
    */
-  void SendFocusInOrOutEvent(mozilla::EventMessage aEventMessage,
+  void FireFocusInOrOutEvent(mozilla::EventMessage aEventMessage,
                              nsIPresShell* aPresShell,
                              nsISupports* aTarget,
                              nsPIDOMWindowOuter* aCurrentFocusedWindow,
                              nsIContent* aCurrentFocusedContent,
                              mozilla::dom::EventTarget* aRelatedTarget = nullptr);
 
   /**
    * Scrolls aContent into view unless the FLAG_NOSCROLL flag is set.
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -29,17 +29,17 @@
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/TimelineConsumers.h"
 #include "mozilla/EventTimelineMarker.h"
 #include "mozilla/TimeStamp.h"
 
 #include "EventListenerService.h"
 #include "GeckoProfiler.h"
 #ifdef MOZ_GECKO_PROFILER
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #endif
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsDOMCID.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsHtml5Atoms.h"
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -3,17 +3,17 @@
 /* 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 "Performance.h"
 
 #include "GeckoProfiler.h"
 #ifdef MOZ_GECKO_PROFILER
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #endif
 #include "PerformanceEntry.h"
 #include "PerformanceMainThread.h"
 #include "PerformanceMark.h"
 #include "PerformanceMeasure.h"
 #include "PerformanceObserver.h"
 #include "PerformanceResourceTiming.h"
 #include "PerformanceService.h"
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -203,16 +203,20 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
   }
 
   VRManager::ManagerInit();
   // Send a message to the UI process that we're done.
   GPUDeviceData data;
   RecvGetDeviceStatus(&data);
   Unused << SendInitComplete(data);
 
+#ifdef XP_WIN
+  DeviceManagerDx::PreloadAttachmentsOnCompositorThread();
+#endif
+
   Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_INITIALIZATION_TIME_MS, mLaunchTime);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 GPUParent::RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint)
 {
   mVsyncBridge = VsyncBridgeParent::Start(Move(aVsyncEndpoint));
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -31,17 +31,17 @@
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for AutoTArray
 #include <stack>
 #include "TextRenderer.h"               // for TextRenderer
 #include <vector>
 #include "GeckoProfiler.h"              // for GeckoProfiler
 #ifdef MOZ_GECKO_PROFILER
-#include "ProfilerMarkers.h"            // for ProfilerMarkers
+#include "ProfilerMarkerPayload.h"      // for LayerTranslationPayload
 #endif
 
 #define CULLING_LOG(...)
 // #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__)
 
 #define DUMP(...) do { if (gfxEnv::DumpDebug()) { printf_stderr(__VA_ARGS__); } } while(0)
 #define XYWH(k)  (k).x, (k).y, (k).width, (k).height
 #define XY(k)    (k).x, (k).y
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1,17 +1,16 @@
 /* -*- 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 "CompositorD3D11.h"
 
 #include "TextureD3D11.h"
-#include "CompositorD3D11Shaders.h"
 
 #include "gfxWindowsPlatform.h"
 #include "nsIWidget.h"
 #include "mozilla/gfx/D3D11Checks.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
 #include "mozilla/gfx/GPUParent.h"
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/layers/ContentHost.h"
@@ -28,178 +27,56 @@
 #include "mozilla/Services.h"
 #include "mozilla/widget/WinCompositorWidget.h"
 
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/Telemetry.h"
 #include "BlendShaderConstants.h"
 
 #include "D3D11ShareHandleImage.h"
+#include "DeviceAttachmentsD3D11.h"
 
 #include <VersionHelpers.h> // For IsWindows8OrGreater
 #include <winsdkver.h>
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 static bool CanUsePartialPresents(ID3D11Device* aDevice);
 
-struct Vertex
-{
-    float position[2];
-};
-
-// {1E4D7BEB-D8EC-4A0B-BF0A-63E6DE129425}
-static const GUID sDeviceAttachmentsD3D11 =
-{ 0x1e4d7beb, 0xd8ec, 0x4a0b, { 0xbf, 0xa, 0x63, 0xe6, 0xde, 0x12, 0x94, 0x25 } };
-// {88041664-C835-4AA8-ACB8-7EC832357ED8}
-static const GUID sLayerManagerCount =
-{ 0x88041664, 0xc835, 0x4aa8, { 0xac, 0xb8, 0x7e, 0xc8, 0x32, 0x35, 0x7e, 0xd8 } };
-
 const FLOAT sBlendFactor[] = { 0, 0, 0, 0 };
 
-static const size_t kInitialMaximumTriangles = 64;
-
 namespace TexSlot {
   static const int RGB = 0;
   static const int Y = 1;
   static const int Cb = 2;
   static const int Cr = 3;
   static const int RGBWhite = 4;
   static const int Mask = 5;
   static const int Backdrop = 6;
 }
 
-struct DeviceAttachmentsD3D11
-{
-  explicit DeviceAttachmentsD3D11(ID3D11Device* device)
-   : mSyncHandle(0),
-     mDevice(device),
-     mInitOkay(true)
-  {}
-
-  bool CreateShaders();
-  bool InitBlendShaders();
-  bool InitSyncObject();
-
-  typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11VertexShader>>
-          VertexShaderArray;
-  typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11PixelShader>>
-          PixelShaderArray;
-
-  RefPtr<ID3D11InputLayout> mInputLayout;
-  RefPtr<ID3D11InputLayout> mDynamicInputLayout;
-
-  RefPtr<ID3D11Buffer> mVertexBuffer;
-  RefPtr<ID3D11Buffer> mDynamicVertexBuffer;
-
-  VertexShaderArray mVSQuadShader;
-  VertexShaderArray mVSQuadBlendShader;
-
-  VertexShaderArray mVSDynamicShader;
-  VertexShaderArray mVSDynamicBlendShader;
-
-  PixelShaderArray mSolidColorShader;
-  PixelShaderArray mRGBAShader;
-  PixelShaderArray mRGBShader;
-  PixelShaderArray mYCbCrShader;
-  PixelShaderArray mNV12Shader;
-  PixelShaderArray mComponentAlphaShader;
-  PixelShaderArray mBlendShader;
-  RefPtr<ID3D11Buffer> mPSConstantBuffer;
-  RefPtr<ID3D11Buffer> mVSConstantBuffer;
-  RefPtr<ID3D11RasterizerState> mRasterizerState;
-  RefPtr<ID3D11SamplerState> mLinearSamplerState;
-  RefPtr<ID3D11SamplerState> mPointSamplerState;
-
-  RefPtr<ID3D11BlendState> mPremulBlendState;
-  RefPtr<ID3D11BlendState> mNonPremulBlendState;
-  RefPtr<ID3D11BlendState> mComponentBlendState;
-  RefPtr<ID3D11BlendState> mDisabledBlendState;
-  RefPtr<IDXGIResource> mSyncTexture;
-  HANDLE mSyncHandle;
-
-private:
-  void InitVertexShader(const ShaderBytes& aShader, VertexShaderArray& aArray, MaskType aMaskType) {
-    InitVertexShader(aShader, getter_AddRefs(aArray[aMaskType]));
-  }
-  void InitPixelShader(const ShaderBytes& aShader, PixelShaderArray& aArray, MaskType aMaskType) {
-    InitPixelShader(aShader, getter_AddRefs(aArray[aMaskType]));
-  }
-  void InitVertexShader(const ShaderBytes& aShader, ID3D11VertexShader** aOut) {
-    if (!mInitOkay) {
-      return;
-    }
-    if (Failed(mDevice->CreateVertexShader(aShader.mData, aShader.mLength, nullptr, aOut), "create vs")) {
-      mInitOkay = false;
-    }
-  }
-  void InitPixelShader(const ShaderBytes& aShader, ID3D11PixelShader** aOut) {
-    if (!mInitOkay) {
-      return;
-    }
-    if (Failed(mDevice->CreatePixelShader(aShader.mData, aShader.mLength, nullptr, aOut), "create ps")) {
-      mInitOkay = false;
-    }
-  }
-
-  bool Failed(HRESULT hr, const char* aContext) {
-    if (SUCCEEDED(hr))
-      return false;
-
-    gfxCriticalNote << "[D3D11] " << aContext << " failed: " << hexa(hr);
-    return true;
-  }
-
-  // Only used during initialization.
-  RefPtr<ID3D11Device> mDevice;
-  bool mInitOkay;
-};
-
 CompositorD3D11::CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget)
   : Compositor(aWidget, aParent)
   , mAttachments(nullptr)
   , mHwnd(nullptr)
   , mDisableSequenceForNextFrame(false)
   , mAllowPartialPresents(false)
   , mVerifyBuffersFailed(false)
   , mIsDoubleBuffered(false)
-  , mMaximumTriangles(kInitialMaximumTriangles)
 {
 }
 
 CompositorD3D11::~CompositorD3D11()
 {
-  if (mDevice) {
-    int referenceCount = 0;
-    UINT size = sizeof(referenceCount);
-    HRESULT hr = mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount);
-    NS_ASSERTION(SUCCEEDED(hr), "Reference count not found on device.");
-    referenceCount--;
-    mDevice->SetPrivateData(sLayerManagerCount,
-                            sizeof(referenceCount),
-                            &referenceCount);
-
-    if (!referenceCount) {
-      DeviceAttachmentsD3D11 *attachments;
-      size = sizeof(attachments);
-      mDevice->GetPrivateData(sDeviceAttachmentsD3D11, &size, &attachments);
-      // No LayerManagers left for this device. Clear out interfaces stored
-      // which hold a reference to the device.
-      mDevice->SetPrivateData(sDeviceAttachmentsD3D11, 0, nullptr);
-
-      delete attachments;
-    }
-  }
 }
 
-
 template<typename VertexType>
 void
 CompositorD3D11::SetVertexBuffer(ID3D11Buffer* aBuffer)
 {
   UINT size = sizeof(VertexType);
   UINT offset = 0;
   mContext->IASetVertexBuffers(0, 1, &aBuffer, &size, &offset);
 }
@@ -211,34 +88,20 @@ CompositorD3D11::SupportsLayerGeometry()
 }
 
 bool
 CompositorD3D11::UpdateDynamicVertexBuffer(const nsTArray<gfx::TexturedTriangle>& aTriangles)
 {
   HRESULT hr;
 
   // Resize the dynamic vertex buffer if needed.
-  if (aTriangles.Length() > mMaximumTriangles) {
-    CD3D11_BUFFER_DESC bufferDesc(sizeof(TexturedVertex) * aTriangles.Length() * 3,
-                                  D3D11_BIND_VERTEX_BUFFER,
-                                  D3D11_USAGE_DYNAMIC,
-                                  D3D11_CPU_ACCESS_WRITE);
-
-    hr = mDevice->CreateBuffer(&bufferDesc, nullptr,
-                               getter_AddRefs(mAttachments->mDynamicVertexBuffer));
-
-    if (Failed(hr, "resize dynamic vertex buffer")) {
-      return false;
-    }
-
-    mMaximumTriangles = aTriangles.Length();
+  if (!mAttachments->EnsureTriangleBuffer(aTriangles.Length())) {
+    return false;
   }
 
-  MOZ_ASSERT(mMaximumTriangles >= aTriangles.Length());
-
   D3D11_MAPPED_SUBRESOURCE resource {};
   hr = mContext->Map(mAttachments->mDynamicVertexBuffer, 0,
                      D3D11_MAP_WRITE_DISCARD, 0, &resource);
 
   if (Failed(hr, "map dynamic vertex buffer")) {
     return false;
   }
 
@@ -255,224 +118,44 @@ CompositorD3D11::UpdateDynamicVertexBuff
 
 bool
 CompositorD3D11::Initialize(nsCString* const out_failureReason)
 {
   ScopedGfxFeatureReporter reporter("D3D11 Layers");
 
   HRESULT hr;
 
-  mDevice = DeviceManagerDx::Get()->GetCompositorDevice();
+  DeviceManagerDx::Get()->GetCompositorDevices(&mDevice, &mAttachments);
   if (!mDevice) {
     gfxCriticalNote << "[D3D11] failed to get compositor device.";
     *out_failureReason = "FEATURE_FAILURE_D3D11_NO_DEVICE";
     return false;
   }
+  if (!mAttachments || !mAttachments->IsValid()) {
+    gfxCriticalNote << "[D3D11] failed to get compositor device attachments";
+    *out_failureReason = mAttachments
+                         ? mAttachments->GetFailureId()
+                         : NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_ATTACHMENTS");
+    return false;
+  }
 
   mDevice->GetImmediateContext(getter_AddRefs(mContext));
   if (!mContext) {
     gfxCriticalNote << "[D3D11] failed to get immediate context";
     *out_failureReason = "FEATURE_FAILURE_D3D11_CONTEXT";
     return false;
   }
 
   mDiagnostics = MakeUnique<DiagnosticsD3D11>(mDevice, mContext);
   mFeatureLevel = mDevice->GetFeatureLevel();
 
   mHwnd = mWidget->AsWindows()->GetHwnd();
 
   memset(&mVSConstants, 0, sizeof(VertexShaderConstants));
 
-  int referenceCount = 0;
-  UINT size = sizeof(referenceCount);
-  // If this isn't there yet it'll fail, count will remain 0, which is correct.
-  mDevice->GetPrivateData(sLayerManagerCount, &size, &referenceCount);
-  referenceCount++;
-  mDevice->SetPrivateData(sLayerManagerCount,
-                          sizeof(referenceCount),
-                          &referenceCount);
-
-  size = sizeof(DeviceAttachmentsD3D11*);
-  if (FAILED(mDevice->GetPrivateData(sDeviceAttachmentsD3D11,
-                                     &size,
-                                     &mAttachments))) {
-    mAttachments = new DeviceAttachmentsD3D11(mDevice);
-    mDevice->SetPrivateData(sDeviceAttachmentsD3D11,
-                            sizeof(mAttachments),
-                            &mAttachments);
-
-    D3D11_INPUT_ELEMENT_DESC layout[] =
-    {
-      { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
-    };
-
-    hr = mDevice->CreateInputLayout(layout,
-                                    sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
-                                    LayerQuadVS,
-                                    sizeof(LayerQuadVS),
-                                    getter_AddRefs(mAttachments->mInputLayout));
-
-    if (Failed(hr, "CreateInputLayout")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT";
-      return false;
-    }
-
-    Vertex vertices[] = { {{0.0, 0.0}}, {{1.0, 0.0}}, {{0.0, 1.0}}, {{1.0, 1.0}} };
-    CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
-    D3D11_SUBRESOURCE_DATA data;
-    data.pSysMem = (void*)vertices;
-
-    hr = mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mAttachments->mVertexBuffer));
-    if (Failed(hr, "create vertex buffer")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER";
-      return false;
-    }
-
-    // Create a second input layout for layers with dynamic geometry.
-    D3D11_INPUT_ELEMENT_DESC dynamicLayout[] =
-    {
-      { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
-      { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
-    };
-
-    hr = mDevice->CreateInputLayout(dynamicLayout,
-                                    sizeof(dynamicLayout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
-                                    LayerDynamicVS,
-                                    sizeof(LayerDynamicVS),
-                                    getter_AddRefs(mAttachments->mDynamicInputLayout));
-
-    if (Failed(hr, "CreateInputLayout")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT";
-      return false;
-    }
-
-    // Allocate memory for the dynamic vertex buffer.
-    bufferDesc = CD3D11_BUFFER_DESC(sizeof(TexturedVertex) * mMaximumTriangles * 3,
-                                    D3D11_BIND_VERTEX_BUFFER,
-                                    D3D11_USAGE_DYNAMIC,
-                                    D3D11_CPU_ACCESS_WRITE);
-
-    hr = mDevice->CreateBuffer(&bufferDesc, nullptr, getter_AddRefs(mAttachments->mDynamicVertexBuffer));
-    if (Failed(hr, "create dynamic vertex buffer")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER";
-      return false;
-    }
-
-    if (!mAttachments->CreateShaders()) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_CREATE_SHADERS";
-      return false;
-    }
-
-    CD3D11_BUFFER_DESC cBufferDesc(sizeof(VertexShaderConstants),
-                                   D3D11_BIND_CONSTANT_BUFFER,
-                                   D3D11_USAGE_DYNAMIC,
-                                   D3D11_CPU_ACCESS_WRITE);
-
-    hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mAttachments->mVSConstantBuffer));
-    if (Failed(hr, "create vs buffer")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_VS_BUFFER";
-      return false;
-    }
-
-    cBufferDesc.ByteWidth = sizeof(PixelShaderConstants);
-    hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mAttachments->mPSConstantBuffer));
-    if (Failed(hr, "create ps buffer")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_PS_BUFFER";
-      return false;
-    }
-
-    CD3D11_RASTERIZER_DESC rastDesc(D3D11_DEFAULT);
-    rastDesc.CullMode = D3D11_CULL_NONE;
-    rastDesc.ScissorEnable = TRUE;
-
-    hr = mDevice->CreateRasterizerState(&rastDesc, getter_AddRefs(mAttachments->mRasterizerState));
-    if (Failed(hr, "create rasterizer")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_RASTERIZER";
-      return false;
-    }
-
-    CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
-    hr = mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mAttachments->mLinearSamplerState));
-    if (Failed(hr, "create linear sampler")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_LINEAR_SAMPLER";
-      return false;
-    }
-
-    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
-    hr = mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mAttachments->mPointSamplerState));
-    if (Failed(hr, "create point sampler")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_POINT_SAMPLER";
-      return false;
-    }
-
-    CD3D11_BLEND_DESC blendDesc(D3D11_DEFAULT);
-    D3D11_RENDER_TARGET_BLEND_DESC rtBlendPremul = {
-      TRUE,
-      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
-      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
-      D3D11_COLOR_WRITE_ENABLE_ALL
-    };
-    blendDesc.RenderTarget[0] = rtBlendPremul;
-    hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mAttachments->mPremulBlendState));
-    if (Failed(hr, "create pm blender")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_PM_BLENDER";
-      return false;
-    }
-
-    D3D11_RENDER_TARGET_BLEND_DESC rtBlendNonPremul = {
-      TRUE,
-      D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
-      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
-      D3D11_COLOR_WRITE_ENABLE_ALL
-    };
-    blendDesc.RenderTarget[0] = rtBlendNonPremul;
-    hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mAttachments->mNonPremulBlendState));
-    if (Failed(hr, "create npm blender")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_NPM_BLENDER";
-      return false;
-    }
-
-    if (gfxPrefs::ComponentAlphaEnabled()) {
-      D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = {
-        TRUE,
-        D3D11_BLEND_ONE,
-        D3D11_BLEND_INV_SRC1_COLOR,
-        D3D11_BLEND_OP_ADD,
-        D3D11_BLEND_ONE,
-        D3D11_BLEND_INV_SRC_ALPHA,
-        D3D11_BLEND_OP_ADD,
-        D3D11_COLOR_WRITE_ENABLE_ALL
-      };
-      blendDesc.RenderTarget[0] = rtBlendComponent;
-      hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mAttachments->mComponentBlendState));
-      if (Failed(hr, "create component blender")) {
-        *out_failureReason = "FEATURE_FAILURE_D3D11_COMP_BLENDER";
-        return false;
-      }
-    }
-
-    D3D11_RENDER_TARGET_BLEND_DESC rtBlendDisabled = {
-      FALSE,
-      D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
-      D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
-      D3D11_COLOR_WRITE_ENABLE_ALL
-    };
-    blendDesc.RenderTarget[0] = rtBlendDisabled;
-    hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mAttachments->mDisabledBlendState));
-    if (Failed(hr, "create null blender")) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_NULL_BLENDER";
-      return false;
-    }
-
-    if (!mAttachments->InitSyncObject()) {
-      *out_failureReason = "FEATURE_FAILURE_D3D11_OBJ_SYNC";
-      return false;
-    }
-  }
-
   RefPtr<IDXGIDevice> dxgiDevice;
   RefPtr<IDXGIAdapter> dxgiAdapter;
 
   mDevice->QueryInterface(dxgiDevice.StartAssignment());
   dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
 
   {
     RefPtr<IDXGIFactory> dxgiFactory;
@@ -1711,101 +1394,16 @@ CompositorD3D11::UpdateRenderTarget()
 
   mDefaultRT = new CompositingRenderTargetD3D11(backBuf, IntPoint(0, 0));
   mDefaultRT->SetSize(mSize.ToUnknownSize());
 
   return true;
 }
 
 bool
-DeviceAttachmentsD3D11::InitSyncObject()
-{
-  // Sync object is not supported on WARP.
-  if (DeviceManagerDx::Get()->IsWARP()) {
-    return true;
-  }
-
-  // It's okay to do this on Windows 8. But for now we'll just bail
-  // whenever we're using WARP.
-  CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
-                             D3D11_BIND_SHADER_RESOURCE |
-                             D3D11_BIND_RENDER_TARGET);
-  desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
-
-  RefPtr<ID3D11Texture2D> texture;
-  HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
-  if (Failed(hr, "create sync texture")) {
-    return false;
-  }
-
-  hr = texture->QueryInterface((IDXGIResource**)getter_AddRefs(mSyncTexture));
-  if (Failed(hr, "QI sync texture")) {
-    return false;
-  }
-
-  hr = mSyncTexture->GetSharedHandle(&mSyncHandle);
-  if (FAILED(hr) || !mSyncHandle) {
-    gfxCriticalError() << "Failed to get SharedHandle for sync texture. Result: "
-                       << hexa(hr);
-    NS_DispatchToMainThread(NS_NewRunnableFunction([] () -> void {
-      Accumulate(Telemetry::D3D11_SYNC_HANDLE_FAILURE, 1);
-    }));
-    return false;
-  }
-
-  return true;
-}
-
-bool
-DeviceAttachmentsD3D11::InitBlendShaders()
-{
-  if (!mVSQuadBlendShader[MaskType::MaskNone]) {
-    InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone);
-    InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask);
-  }
-
-  if (!mVSDynamicBlendShader[MaskType::MaskNone]) {
-    InitVertexShader(sLayerDynamicBlendVS, mVSDynamicBlendShader, MaskType::MaskNone);
-    InitVertexShader(sLayerDynamicBlendMaskVS, mVSDynamicBlendShader, MaskType::Mask);
-  }
-
-  if (!mBlendShader[MaskType::MaskNone]) {
-    InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone);
-  }
-  return mInitOkay;
-}
-
-bool
-DeviceAttachmentsD3D11::CreateShaders()
-{
-  InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone);
-  InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask);
-
-  InitVertexShader(sLayerDynamicVS, mVSDynamicShader, MaskType::MaskNone);
-  InitVertexShader(sLayerDynamicMaskVS, mVSDynamicShader, MaskType::Mask);
-
-  InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone);
-  InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask);
-  InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone);
-  InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask);
-  InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone);
-  InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask);
-  InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone);
-  InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask);
-  InitPixelShader(sNV12Shader, mNV12Shader, MaskType::MaskNone);
-  InitPixelShader(sNV12ShaderMask, mNV12Shader, MaskType::Mask);
-  if (gfxPrefs::ComponentAlphaEnabled()) {
-    InitPixelShader(sComponentAlphaShader, mComponentAlphaShader, MaskType::MaskNone);
-    InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask);
-  }
-
-  return mInitOkay;
-}
-
-bool
 CompositorD3D11::UpdateConstantBuffers()
 {
   HRESULT hr;
   D3D11_MAPPED_SUBRESOURCE resource;
   resource.pData = nullptr;
 
   hr = mContext->Map(mAttachments->mVSConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
   if (FAILED(hr) || !resource.pData) {
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -7,44 +7,26 @@
 #define MOZILLA_GFX_COMPOSITORD3D11_H
 
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 #include "mozilla/layers/Compositor.h"
 #include "TextureD3D11.h"
 #include <d3d11.h>
 #include <dxgi1_2.h>
+#include "ShaderDefinitionsD3D11.h"
 
 class nsWidget;
 
 namespace mozilla {
 namespace layers {
 
 #define LOGD3D11(param)
 
-struct VertexShaderConstants
-{
-  float layerTransform[4][4];
-  float projection[4][4];
-  float renderTargetOffset[4];
-  gfx::Rect textureCoords;
-  gfx::Rect layerQuad;
-  float maskTransform[4][4];
-  float backdropTransform[4][4];
-};
-
-struct PixelShaderConstants
-{
-  float layerColor[4];
-  float layerOpacity[4];
-  int blendConfig[4];
-  float yuvColorMatrix[3][4];
-};
-
-struct DeviceAttachmentsD3D11;
+class DeviceAttachmentsD3D11;
 class DiagnosticsD3D11;
 
 class CompositorD3D11 : public Compositor
 {
 public:
   CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget);
   ~CompositorD3D11();
 
@@ -228,17 +210,17 @@ private:
   RefPtr<ID3D11DeviceContext> mContext;
   RefPtr<ID3D11Device> mDevice;
   RefPtr<IDXGISwapChain> mSwapChain;
   RefPtr<CompositingRenderTargetD3D11> mDefaultRT;
   RefPtr<CompositingRenderTargetD3D11> mCurrentRT;
 
   RefPtr<ID3D11Query> mQuery;
 
-  DeviceAttachmentsD3D11* mAttachments;
+  RefPtr<DeviceAttachmentsD3D11> mAttachments;
   UniquePtr<DiagnosticsD3D11> mDiagnostics;
 
   LayoutDeviceIntSize mSize;
 
   HWND mHwnd;
 
   D3D_FEATURE_LEVEL mFeatureLevel;
 
@@ -249,16 +231,14 @@ private:
   bool mIsDoubleBuffered;
 
   gfx::IntRegion mFrontBufferInvalid;
   gfx::IntRegion mBackBufferInvalid;
   // This is the clip rect applied to the default DrawTarget (i.e. the window)
   gfx::IntRect mCurrentClip;
 
   bool mVerifyBuffersFailed;
-
-  size_t mMaximumTriangles;
 };
 
 }
 }
 
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d11/DeviceAttachmentsD3D11.cpp
@@ -0,0 +1,361 @@
+/* -*- 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 "DeviceAttachmentsD3D11.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/layers/Compositor.h"
+#include "CompositorD3D11Shaders.h"
+#include "gfxPrefs.h"
+#include "ShaderDefinitionsD3D11.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace gfx;
+
+static const size_t kInitialMaximumTriangles = 64;
+
+DeviceAttachmentsD3D11::DeviceAttachmentsD3D11(ID3D11Device* device)
+ : mSyncHandle(0),
+   mMaximumTriangles(kInitialMaximumTriangles),
+   mDevice(device),
+   mContinueInit(true),
+   mInitialized(false)
+{
+}
+
+DeviceAttachmentsD3D11::~DeviceAttachmentsD3D11()
+{
+}
+
+/* static */ RefPtr<DeviceAttachmentsD3D11>
+DeviceAttachmentsD3D11::Create(ID3D11Device* aDevice)
+{
+  // We don't return null even if the attachments object even if it fails to
+  // initialize, so the compositor can grab the failure ID.
+  RefPtr<DeviceAttachmentsD3D11> attachments = new DeviceAttachmentsD3D11(aDevice);
+  attachments->Initialize();
+  return attachments.forget();
+}
+
+bool
+DeviceAttachmentsD3D11::Initialize()
+{
+  D3D11_INPUT_ELEMENT_DESC layout[] =
+  {
+    { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+  };
+
+  HRESULT hr;
+  hr = mDevice->CreateInputLayout(layout,
+                                  sizeof(layout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
+                                  LayerQuadVS,
+                                  sizeof(LayerQuadVS),
+                                  getter_AddRefs(mInputLayout));
+
+  if (Failed(hr, "CreateInputLayout")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT";
+    return false;
+  }
+
+  Vertex vertices[] = { {{0.0, 0.0}}, {{1.0, 0.0}}, {{0.0, 1.0}}, {{1.0, 1.0}} };
+  CD3D11_BUFFER_DESC bufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
+  D3D11_SUBRESOURCE_DATA data;
+  data.pSysMem = (void*)vertices;
+
+  hr = mDevice->CreateBuffer(&bufferDesc, &data, getter_AddRefs(mVertexBuffer));
+  if (Failed(hr, "create vertex buffer")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER";
+    return false;
+  }
+
+  // Create a second input layout for layers with dynamic geometry.
+  D3D11_INPUT_ELEMENT_DESC dynamicLayout[] =
+  {
+    { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+  };
+
+  hr = mDevice->CreateInputLayout(dynamicLayout,
+                                  sizeof(dynamicLayout) / sizeof(D3D11_INPUT_ELEMENT_DESC),
+                                  LayerDynamicVS,
+                                  sizeof(LayerDynamicVS),
+                                  getter_AddRefs(mDynamicInputLayout));
+
+  if (Failed(hr, "CreateInputLayout")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_INPUT_LAYOUT";
+    return false;
+  }
+
+  // Allocate memory for the dynamic vertex buffer.
+  bufferDesc = CD3D11_BUFFER_DESC(sizeof(TexturedVertex) * mMaximumTriangles * 3,
+                                  D3D11_BIND_VERTEX_BUFFER,
+                                  D3D11_USAGE_DYNAMIC,
+                                  D3D11_CPU_ACCESS_WRITE);
+
+  hr = mDevice->CreateBuffer(&bufferDesc, nullptr, getter_AddRefs(mDynamicVertexBuffer));
+  if (Failed(hr, "create dynamic vertex buffer")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_VERTEX_BUFFER";
+    return false;
+  }
+
+  if (!CreateShaders()) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_CREATE_SHADERS";
+    return false;
+  }
+
+  CD3D11_BUFFER_DESC cBufferDesc(sizeof(VertexShaderConstants),
+                                 D3D11_BIND_CONSTANT_BUFFER,
+                                 D3D11_USAGE_DYNAMIC,
+                                 D3D11_CPU_ACCESS_WRITE);
+
+  hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mVSConstantBuffer));
+  if (Failed(hr, "create vs buffer")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_VS_BUFFER";
+    return false;
+  }
+
+  cBufferDesc.ByteWidth = sizeof(PixelShaderConstants);
+  hr = mDevice->CreateBuffer(&cBufferDesc, nullptr, getter_AddRefs(mPSConstantBuffer));
+  if (Failed(hr, "create ps buffer")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_PS_BUFFER";
+    return false;
+  }
+
+  CD3D11_RASTERIZER_DESC rastDesc(D3D11_DEFAULT);
+  rastDesc.CullMode = D3D11_CULL_NONE;
+  rastDesc.ScissorEnable = TRUE;
+
+  hr = mDevice->CreateRasterizerState(&rastDesc, getter_AddRefs(mRasterizerState));
+  if (Failed(hr, "create rasterizer")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_RASTERIZER";
+    return false;
+  }
+
+  CD3D11_SAMPLER_DESC samplerDesc(D3D11_DEFAULT);
+  hr = mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mLinearSamplerState));
+  if (Failed(hr, "create linear sampler")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_LINEAR_SAMPLER";
+    return false;
+  }
+
+  samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+  hr = mDevice->CreateSamplerState(&samplerDesc, getter_AddRefs(mPointSamplerState));
+  if (Failed(hr, "create point sampler")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_POINT_SAMPLER";
+    return false;
+  }
+
+  CD3D11_BLEND_DESC blendDesc(D3D11_DEFAULT);
+  D3D11_RENDER_TARGET_BLEND_DESC rtBlendPremul = {
+    TRUE,
+    D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+    D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+    D3D11_COLOR_WRITE_ENABLE_ALL
+  };
+  blendDesc.RenderTarget[0] = rtBlendPremul;
+  hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mPremulBlendState));
+  if (Failed(hr, "create pm blender")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_PM_BLENDER";
+    return false;
+  }
+
+  D3D11_RENDER_TARGET_BLEND_DESC rtBlendNonPremul = {
+    TRUE,
+    D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+    D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+    D3D11_COLOR_WRITE_ENABLE_ALL
+  };
+  blendDesc.RenderTarget[0] = rtBlendNonPremul;
+  hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mNonPremulBlendState));
+  if (Failed(hr, "create npm blender")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_NPM_BLENDER";
+    return false;
+  }
+
+  if (gfxPrefs::ComponentAlphaEnabled()) {
+    D3D11_RENDER_TARGET_BLEND_DESC rtBlendComponent = {
+      TRUE,
+      D3D11_BLEND_ONE,
+      D3D11_BLEND_INV_SRC1_COLOR,
+      D3D11_BLEND_OP_ADD,
+      D3D11_BLEND_ONE,
+      D3D11_BLEND_INV_SRC_ALPHA,
+      D3D11_BLEND_OP_ADD,
+      D3D11_COLOR_WRITE_ENABLE_ALL
+    };
+    blendDesc.RenderTarget[0] = rtBlendComponent;
+    hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mComponentBlendState));
+    if (Failed(hr, "create component blender")) {
+      mInitFailureId = "FEATURE_FAILURE_D3D11_COMP_BLENDER";
+      return false;
+    }
+  }
+
+  D3D11_RENDER_TARGET_BLEND_DESC rtBlendDisabled = {
+    FALSE,
+    D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+    D3D11_BLEND_ONE, D3D11_BLEND_INV_SRC_ALPHA, D3D11_BLEND_OP_ADD,
+    D3D11_COLOR_WRITE_ENABLE_ALL
+  };
+  blendDesc.RenderTarget[0] = rtBlendDisabled;
+  hr = mDevice->CreateBlendState(&blendDesc, getter_AddRefs(mDisabledBlendState));
+  if (Failed(hr, "create null blender")) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_NULL_BLENDER";
+    return false;
+  }
+
+  if (!InitSyncObject()) {
+    mInitFailureId = "FEATURE_FAILURE_D3D11_OBJ_SYNC";
+    return false;
+  }
+
+  mInitialized = true;
+  return true;
+}
+
+bool
+DeviceAttachmentsD3D11::InitSyncObject()
+{
+  // Sync object is not supported on WARP.
+  if (DeviceManagerDx::Get()->IsWARP()) {
+    return true;
+  }
+
+  // It's okay to do this on Windows 8. But for now we'll just bail
+  // whenever we're using WARP.
+  CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1,
+                             D3D11_BIND_SHADER_RESOURCE |
+                             D3D11_BIND_RENDER_TARGET);
+  desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+
+  RefPtr<ID3D11Texture2D> texture;
+  HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
+  if (Failed(hr, "create sync texture")) {
+    return false;
+  }
+
+  hr = texture->QueryInterface((IDXGIResource**)getter_AddRefs(mSyncTexture));
+  if (Failed(hr, "QI sync texture")) {
+    return false;
+  }
+
+  hr = mSyncTexture->GetSharedHandle(&mSyncHandle);
+  if (FAILED(hr) || !mSyncHandle) {
+    gfxCriticalError() << "Failed to get SharedHandle for sync texture. Result: "
+                       << hexa(hr);
+    NS_DispatchToMainThread(NS_NewRunnableFunction([] () -> void {
+      Accumulate(Telemetry::D3D11_SYNC_HANDLE_FAILURE, 1);
+    }));
+    return false;
+  }
+
+  return true;
+}
+
+bool
+DeviceAttachmentsD3D11::InitBlendShaders()
+{
+  if (!mVSQuadBlendShader[MaskType::MaskNone]) {
+    InitVertexShader(sLayerQuadBlendVS, mVSQuadBlendShader, MaskType::MaskNone);
+    InitVertexShader(sLayerQuadBlendMaskVS, mVSQuadBlendShader, MaskType::Mask);
+  }
+
+  if (!mVSDynamicBlendShader[MaskType::MaskNone]) {
+    InitVertexShader(sLayerDynamicBlendVS, mVSDynamicBlendShader, MaskType::MaskNone);
+    InitVertexShader(sLayerDynamicBlendMaskVS, mVSDynamicBlendShader, MaskType::Mask);
+  }
+
+  if (!mBlendShader[MaskType::MaskNone]) {
+    InitPixelShader(sBlendShader, mBlendShader, MaskType::MaskNone);
+  }
+  return mContinueInit;
+}
+
+bool
+DeviceAttachmentsD3D11::CreateShaders()
+{
+  InitVertexShader(sLayerQuadVS, mVSQuadShader, MaskType::MaskNone);
+  InitVertexShader(sLayerQuadMaskVS, mVSQuadShader, MaskType::Mask);
+
+  InitVertexShader(sLayerDynamicVS, mVSDynamicShader, MaskType::MaskNone);
+  InitVertexShader(sLayerDynamicMaskVS, mVSDynamicShader, MaskType::Mask);
+
+  InitPixelShader(sSolidColorShader, mSolidColorShader, MaskType::MaskNone);
+  InitPixelShader(sSolidColorShaderMask, mSolidColorShader, MaskType::Mask);
+  InitPixelShader(sRGBShader, mRGBShader, MaskType::MaskNone);
+  InitPixelShader(sRGBShaderMask, mRGBShader, MaskType::Mask);
+  InitPixelShader(sRGBAShader, mRGBAShader, MaskType::MaskNone);
+  InitPixelShader(sRGBAShaderMask, mRGBAShader, MaskType::Mask);
+  InitPixelShader(sYCbCrShader, mYCbCrShader, MaskType::MaskNone);
+  InitPixelShader(sYCbCrShaderMask, mYCbCrShader, MaskType::Mask);
+  InitPixelShader(sNV12Shader, mNV12Shader, MaskType::MaskNone);
+  InitPixelShader(sNV12ShaderMask, mNV12Shader, MaskType::Mask);
+  if (gfxPrefs::ComponentAlphaEnabled()) {
+    InitPixelShader(sComponentAlphaShader, mComponentAlphaShader, MaskType::MaskNone);
+    InitPixelShader(sComponentAlphaShaderMask, mComponentAlphaShader, MaskType::Mask);
+  }
+
+  return mContinueInit;
+}
+
+void
+DeviceAttachmentsD3D11::InitVertexShader(const ShaderBytes& aShader, ID3D11VertexShader** aOut)
+{
+  if (!mContinueInit) {
+    return;
+  }
+  if (Failed(mDevice->CreateVertexShader(aShader.mData, aShader.mLength, nullptr, aOut), "create vs")) {
+    mContinueInit = false;
+  }
+}
+
+void
+DeviceAttachmentsD3D11::InitPixelShader(const ShaderBytes& aShader, ID3D11PixelShader** aOut)
+{
+  if (!mContinueInit) {
+    return;
+  }
+  if (Failed(mDevice->CreatePixelShader(aShader.mData, aShader.mLength, nullptr, aOut), "create ps")) {
+    mContinueInit = false;
+  }
+}
+
+bool
+DeviceAttachmentsD3D11::Failed(HRESULT hr, const char* aContext)
+{
+  if (SUCCEEDED(hr)) {
+    return false;
+  }
+
+  gfxCriticalNote << "[D3D11] " << aContext << " failed: " << hexa(hr);
+  return true;
+}
+
+bool
+DeviceAttachmentsD3D11::EnsureTriangleBuffer(size_t aNumTriangles)
+{
+  if (aNumTriangles > mMaximumTriangles) {
+    CD3D11_BUFFER_DESC bufferDesc(sizeof(TexturedVertex) * aNumTriangles * 3,
+                                  D3D11_BIND_VERTEX_BUFFER,
+                                  D3D11_USAGE_DYNAMIC,
+                                  D3D11_CPU_ACCESS_WRITE);
+
+    HRESULT hr =
+      mDevice->CreateBuffer(&bufferDesc, nullptr, getter_AddRefs(mDynamicVertexBuffer));
+
+    if (Failed(hr, "resize dynamic vertex buffer")) {
+      return false;
+    }
+
+    mMaximumTriangles = aNumTriangles;
+  }
+
+  MOZ_ASSERT(mMaximumTriangles >= aNumTriangles);
+  return true;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d11/DeviceAttachmentsD3D11.h
@@ -0,0 +1,109 @@
+/* -*- 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_d3d11_DeviceAttachmentsD3D11_h
+#define mozilla_gfx_layers_d3d11_DeviceAttachmentsD3D11_h
+
+#include "mozilla/EnumeratedArray.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/gfx/DeviceManagerDx.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include <d3d11.h>
+#include <dxgi1_2.h>
+
+struct ShaderBytes;
+
+namespace mozilla {
+namespace layers {
+
+class DeviceAttachmentsD3D11
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceAttachmentsD3D11);
+
+public:
+  static RefPtr<DeviceAttachmentsD3D11> Create(ID3D11Device* aDevice);
+
+  bool InitBlendShaders();
+  bool EnsureTriangleBuffer(size_t aNumTriangles);
+
+  bool IsValid() const {
+    return mInitialized;
+  }
+  const nsCString& GetFailureId() const {
+    MOZ_ASSERT(!IsValid());
+    return mInitFailureId;
+  }
+
+  typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11VertexShader>>
+          VertexShaderArray;
+  typedef EnumeratedArray<MaskType, MaskType::NumMaskTypes, RefPtr<ID3D11PixelShader>>
+          PixelShaderArray;
+
+  RefPtr<ID3D11InputLayout> mInputLayout;
+  RefPtr<ID3D11InputLayout> mDynamicInputLayout;
+
+  RefPtr<ID3D11Buffer> mVertexBuffer;
+  RefPtr<ID3D11Buffer> mDynamicVertexBuffer;
+
+  VertexShaderArray mVSQuadShader;
+  VertexShaderArray mVSQuadBlendShader;
+
+  VertexShaderArray mVSDynamicShader;
+  VertexShaderArray mVSDynamicBlendShader;
+
+  PixelShaderArray mSolidColorShader;
+  PixelShaderArray mRGBAShader;
+  PixelShaderArray mRGBShader;
+  PixelShaderArray mYCbCrShader;
+  PixelShaderArray mNV12Shader;
+  PixelShaderArray mComponentAlphaShader;
+  PixelShaderArray mBlendShader;
+  RefPtr<ID3D11Buffer> mPSConstantBuffer;
+  RefPtr<ID3D11Buffer> mVSConstantBuffer;
+  RefPtr<ID3D11RasterizerState> mRasterizerState;
+  RefPtr<ID3D11SamplerState> mLinearSamplerState;
+  RefPtr<ID3D11SamplerState> mPointSamplerState;
+
+  RefPtr<ID3D11BlendState> mPremulBlendState;
+  RefPtr<ID3D11BlendState> mNonPremulBlendState;
+  RefPtr<ID3D11BlendState> mComponentBlendState;
+  RefPtr<ID3D11BlendState> mDisabledBlendState;
+  RefPtr<IDXGIResource> mSyncTexture;
+  HANDLE mSyncHandle;
+
+private:
+  explicit DeviceAttachmentsD3D11(ID3D11Device* device);
+  ~DeviceAttachmentsD3D11();
+
+  bool Initialize();
+  bool CreateShaders();
+  bool InitSyncObject();
+
+  void InitVertexShader(const ShaderBytes& aShader, VertexShaderArray& aArray, MaskType aMaskType) {
+    InitVertexShader(aShader, getter_AddRefs(aArray[aMaskType]));
+  }
+  void InitPixelShader(const ShaderBytes& aShader, PixelShaderArray& aArray, MaskType aMaskType) {
+    InitPixelShader(aShader, getter_AddRefs(aArray[aMaskType]));
+  }
+
+  void InitVertexShader(const ShaderBytes& aShader, ID3D11VertexShader** aOut);
+  void InitPixelShader(const ShaderBytes& aShader, ID3D11PixelShader** aOut);
+
+  bool Failed(HRESULT hr, const char* aContext);
+
+private:
+  size_t mMaximumTriangles;
+
+  // Only used during initialization.
+  RefPtr<ID3D11Device> mDevice;
+  bool mContinueInit;
+  bool mInitialized;
+  nsCString mInitFailureId;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_d3d11_DeviceAttachmentsD3D11_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d11/ShaderDefinitionsD3D11.h
@@ -0,0 +1,41 @@
+/* -*- 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_d3d11_ShaderDefinitionsD3D11_h
+#define mozilla_gfx_layers_d3d11_ShaderDefinitionsD3D11_h
+
+#include "mozilla/gfx/Rect.h"
+
+namespace mozilla {
+namespace layers {
+
+struct VertexShaderConstants
+{
+  float layerTransform[4][4];
+  float projection[4][4];
+  float renderTargetOffset[4];
+  gfx::Rect textureCoords;
+  gfx::Rect layerQuad;
+  float maskTransform[4][4];
+  float backdropTransform[4][4];
+};
+
+struct PixelShaderConstants
+{
+  float layerColor[4];
+  float layerOpacity[4];
+  int blendConfig[4];
+  float yuvColorMatrix[3][4];
+};
+
+struct Vertex
+{
+    float position[2];
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_d3d11_ShaderDefinitionsD3D11_h
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -77,17 +77,17 @@
 #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_GECKO_PROFILER
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.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"
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -57,27 +57,30 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         'TextureDIB.cpp',
     ]
     EXPORTS.mozilla.layers += [
         'TextureDIB.h',
     ]
     if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
         EXPORTS.mozilla.layers += [
             'd3d11/CompositorD3D11.h',
+            'd3d11/DeviceAttachmentsD3D11.h',
             'd3d11/DiagnosticsD3D11.h',
             'd3d11/HelpersD3D11.h',
             'd3d11/ReadbackManagerD3D11.h',
+            'd3d11/ShaderDefinitionsD3D11.h',
             'd3d11/TextureD3D11.h',
         ]
         UNIFIED_SOURCES += [
             'd3d11/DiagnosticsD3D11.cpp',
             'd3d11/TextureD3D11.cpp',
         ]
         SOURCES += [
             'd3d11/CompositorD3D11.cpp',
+            'd3d11/DeviceAttachmentsD3D11.cpp',
             'd3d11/ReadbackManagerD3D11.cpp',
         ]
 
 EXPORTS.gfxipc += [
     'ipc/ShadowLayerUtils.h',
 ]
 
 EXPORTS.mozilla.dom += [
--- a/gfx/thebes/ContextStateTracker.cpp
+++ b/gfx/thebes/ContextStateTracker.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "ContextStateTracker.h"
 #include "GLContext.h"
 #ifdef MOZ_GECKO_PROFILER
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #endif
 
 namespace mozilla {
 
 void
 ContextStateTrackerOGL::PushOGLSection(GLContext* aGL, const char* aSectionName)
 {
   if (!profiler_feature_active("gpu")) {
--- a/gfx/thebes/DeviceManagerDx.cpp
+++ b/gfx/thebes/DeviceManagerDx.cpp
@@ -10,16 +10,17 @@
 #include "gfxPrefs.h"
 #include "gfxWindowsPlatform.h"
 #include "mozilla/D3DMessageUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/gfx/GraphicsMessages.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/DeviceAttachmentsD3D11.h"
 #include "nsIGfxInfo.h"
 #include <d3d11.h>
 #include <ddraw.h>
 
 namespace mozilla {
 namespace gfx {
 
 using namespace mozilla::widget;
@@ -597,16 +598,17 @@ DeviceManagerDx::CreateDecoderDevice()
 }
 
 void
 DeviceManagerDx::ResetDevices()
 {
   MutexAutoLock lock(mDeviceLock);
 
   mAdapter = nullptr;
+  mCompositorAttachments = nullptr;
   mCompositorDevice = nullptr;
   mContentDevice = nullptr;
   mDeviceStatus = Nothing();
   mDeviceResetReason = Nothing();
   Factory::SetDirect3D11Device(nullptr);
 }
 
 bool
@@ -895,10 +897,66 @@ DeviceManagerDx::InitializeDirectDraw()
 }
 
 IDirectDraw7*
 DeviceManagerDx::GetDirectDraw()
 {
   return mDirectDraw;
 }
 
+void
+DeviceManagerDx::GetCompositorDevices(RefPtr<ID3D11Device>* aOutDevice,
+                                      RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments)
+{
+  MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
+
+  RefPtr<ID3D11Device> device;
+  {
+    MutexAutoLock lock(mDeviceLock);
+    if (!mCompositorDevice) {
+      return;
+    }
+    if (mCompositorAttachments) {
+      *aOutDevice = mCompositorDevice;
+      *aOutAttachments = mCompositorAttachments;
+      return;
+    }
+
+    // Otherwise, we'll try to create attachments outside the lock.
+    device = mCompositorDevice;
+  }
+
+  // We save the attachments object even if it fails to initialize, so the
+  // compositor can grab the failure ID.
+  RefPtr<layers::DeviceAttachmentsD3D11> attachments =
+    layers::DeviceAttachmentsD3D11::Create(device);
+  {
+    MutexAutoLock lock(mDeviceLock);
+    if (device != mCompositorDevice) {
+      return;
+    }
+    mCompositorAttachments = attachments;
+  }
+
+  *aOutDevice = device;
+  *aOutAttachments = attachments;
+}
+
+/* static */ void
+DeviceManagerDx::PreloadAttachmentsOnCompositorThread()
+{
+  MessageLoop* loop = layers::CompositorThreadHolder::Loop();
+  if (!loop) {
+    return;
+  }
+
+  RefPtr<Runnable> task = NS_NewRunnableFunction([]() -> void {
+    if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
+      RefPtr<ID3D11Device> device;
+      RefPtr<layers::DeviceAttachmentsD3D11> attachments;
+      dm->GetCompositorDevices(&device, &attachments);
+    }
+  });
+  loop->PostTask(task.forget());
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/thebes/DeviceManagerDx.h
+++ b/gfx/thebes/DeviceManagerDx.h
@@ -30,16 +30,19 @@
 #define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096
 #endif
 
 struct ID3D11Device;
 struct IDirectDraw7;
 
 namespace mozilla {
 class ScopedGfxFeatureReporter;
+namespace layers {
+class DeviceAttachmentsD3D11;
+} // namespace layers
 
 namespace gfx {
 class FeatureState;
 
 class DeviceManagerDx final
 {
 public:
   static void Init();
@@ -65,16 +68,19 @@ public:
   // upload texture data during the CreateTexture2D
   // call. This crashes on some devices, so we might
   // need to avoid it.
   bool CanInitializeKeyedMutexTextures();
 
   bool CreateCompositorDevices();
   void CreateContentDevices();
 
+  void GetCompositorDevices(RefPtr<ID3D11Device>* aOutDevice,
+                            RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments);
+
   void ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus);
   void ExportDeviceInfo(D3D11DeviceStatus* aOut);
 
   void ResetDevices();
   void InitializeDirectDraw();
 
   // Reset and reacquire the devices if a reset has happened.
   // Returns whether a reset occurred not whether reacquiring
@@ -88,16 +94,20 @@ public:
   // Device reset helpers.
   bool HasDeviceReset(DeviceResetReason* aOutReason = nullptr);
 
   // Note: these set the cached device reset reason, which will be picked up
   // on the next frame.
   void ForceDeviceReset(ForcedDeviceResetReason aReason);
   void NotifyD3D9DeviceReset();
 
+  // Pre-load any compositor resources that are expensive, and are needed when we
+  // attempt to create a compositor.
+  static void PreloadAttachmentsOnCompositorThread();
+
 private:
   IDXGIAdapter1 *GetDXGIAdapter();
 
   void DisableD3D11AfterCrash();
 
   void CreateCompositorDevice(mozilla::gfx::FeatureState& d3d11);
   bool CreateCompositorDeviceHelper(
       mozilla::gfx::FeatureState& aD3d11,
@@ -133,16 +143,17 @@ private:
   nsModuleHandle mD3D11Module;
 
   mozilla::Mutex mDeviceLock;
   nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
   RefPtr<IDXGIAdapter1> mAdapter;
   RefPtr<ID3D11Device> mCompositorDevice;
   RefPtr<ID3D11Device> mContentDevice;
   RefPtr<ID3D11Device> mDecoderDevice;
+  RefPtr<layers::DeviceAttachmentsD3D11> mCompositorAttachments;
   bool mCompositorDeviceSupportsVideo;
 
   Maybe<D3D11DeviceStatus> mDeviceStatus;
 
   nsModuleHandle mDirectDrawDLL;
   RefPtr<IDirectDraw7> mDirectDraw;
 
   Maybe<DeviceResetReason> mDeviceResetReason;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -46,16 +46,17 @@
 #elif defined(MOZ_WIDGET_GTK)
 #include "gfxPlatformGtk.h"
 #elif defined(ANDROID)
 #include "gfxAndroidPlatform.h"
 #endif
 
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
+#include "mozilla/gfx/DeviceManagerDx.h"
 #endif
 
 #include "nsGkAtoms.h"
 #include "gfxPlatformFontList.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "nsUnicodeProperties.h"
 #include "harfbuzz/hb.h"
@@ -959,16 +960,19 @@ gfxPlatform::InitLayersIPC()
     sLayersIPCIsUp = true;
 
     if (XRE_IsParentProcess())
     {
         if (gfxVars::UseWebRender()) {
             wr::RenderThread::Start();
         }
         layers::CompositorThreadHolder::Start();
+#ifdef XP_WIN
+        gfx::DeviceManagerDx::PreloadAttachmentsOnCompositorThread();
+#endif
     }
 }
 
 /* static */ void
 gfxPlatform::ShutdownLayersIPC()
 {
     if (!sLayersIPCIsUp) {
       return;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -66,16 +66,17 @@
 
 #include "base/thread.h"
 #include "gfxPrefs.h"
 #include "gfxConfig.h"
 #include "VsyncSource.h"
 #include "DriverCrashGuard.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
+#include "mozilla/layers/DeviceAttachmentsD3D11.h"
 #include "D3D11Checks.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::widget;
 using namespace mozilla::image;
 
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -166247,17 +166247,17 @@
    "e3daa6a1f0c1d87f0b02909affcf190bd29eadf9",
    "testharness"
   ],
   "dom/nodes/Element-children.html": [
    "e3fe31ea198922fe64fbf985ae99d1cd4512567a",
    "testharness"
   ],
   "dom/nodes/Element-classlist.html": [
-   "612d218e8252405070a6c075d6eb5aa5f36772c1",
+   "7e3b68e65468fba0708f4084a9b2f6af93edde90",
    "testharness"
   ],
   "dom/nodes/Element-closest.html": [
    "4171fb8b70948ba2617e05b118aaf5d9367e916f",
    "testharness"
   ],
   "dom/nodes/Element-firstElementChild-entity-xhtml.xhtml": [
    "d8babfc580fb43cfec2a2600be979ae769087c05",
@@ -166391,17 +166391,17 @@
    "d6bb6d9f107f2d3ffd3c86793185eeb4336df834",
    "testharness"
   ],
   "dom/nodes/Element-webkitMatchesSelector.html": [
    "31934621453740439f9b318c0bb8b180ac3071c3",
    "testharness"
   ],
   "dom/nodes/MutationObserver-attributes.html": [
-   "f0695f2e137e34f015d9831d68b89c669d515c75",
+   "0a224c3dc64de0c4cf1fdc895a2c52667be2134f",
    "testharness"
   ],
   "dom/nodes/MutationObserver-characterData.html": [
    "ecf8cba9842dc6fed4b678a40c039389088c9d6e",
    "testharness"
   ],
   "dom/nodes/MutationObserver-childList.html": [
    "91826df379f2edb53ab2d5d408905636512eeb28",
@@ -211703,17 +211703,17 @@
    "55100f7d505bc8cbc966ced0d1337ed78534a553",
    "testharness"
   ],
   "web-animations/animation-model/animation-types/property-list.js": [
    "a07677026775e050539fbec9fe518fe762025923",
    "support"
   ],
   "web-animations/animation-model/animation-types/property-types.js": [
-   "564158b80368dc7ff9aa8fa0140343289762c413",
+   "d62c58c9dfb52b7147008c1080c8a5d4f4d72a93",
    "support"
   ],
   "web-animations/animation-model/animation-types/spacing-keyframes-filters.html": [
    "bd771a8a18245560221d92ea3495f81918c09848",
    "testharness"
   ],
   "web-animations/animation-model/animation-types/spacing-keyframes-shapes.html": [
    "03c3ab6815cfa96c07d5f95b6059fb276c50a25f",
--- a/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property.html.ini
+++ b/testing/web-platform/meta/web-animations/animation-model/animation-types/interpolation-per-property.html.ini
@@ -1,25 +1,9 @@
 prefs: [layout.css.contain.enabled:true, layout.css.initial-letter.enabled:true, layout.css.overflow-clip-box.enabled:true, layout.css.shape-outside.enabled:true]
 [interpolation-per-property.html]
   type: testharness
-  [flex-basis supports animating as combination units "px" and "%"]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1291187
-
-  [flex-basis supports animating as combination units "%" and "em"]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1291187
-
   [filterList has testInterpolation function]
     expected: FAIL
 
   [filter (type: filterList) has testInterpolation function]
     expected: FAIL
 
-  [word-spacing supports animating as combination units "px" and "%"]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1291187
-
-  [word-spacing supports animating as combination units "%" and "em"]
-    expected: FAIL
-    bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1291187
-
--- a/testing/web-platform/mozilla/meta/MANIFEST.json
+++ b/testing/web-platform/mozilla/meta/MANIFEST.json
@@ -833,17 +833,17 @@
   }
  },
  "paths": {
   "./placeholder": [
    "74e16eb87ecdfeb2dfc28f36e0c73a584abdf9c2",
    "support"
   ],
   "dom/classList.html": [
-   "6d9b7f24be9c7e2ccf504c8fe05e93bbc01fd7c6",
+   "f289334e7b3486259b9aae54b4282a7211b8813e",
    "testharness"
   ],
   "fetch/api/redirect/redirect-referrer-mixed-content.js": [
    "f9d7ec9cf9fa8c847e45664b05482e3f8c191385",
    "support"
   ],
   "fetch/api/redirect/redirect-referrer.https.html": [
    "99cbd16b78771f35e075e4012d8dbc5dce3209c0",
--- a/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js
+++ b/testing/web-platform/tests/web-animations/animation-model/animation-types/property-types.js
@@ -80,30 +80,26 @@ const discreteType = {
 const lengthType = {
   testInterpolation: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['10px', '50px'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px' },
-                            { time: 500,  expected: '30px' },
-                            { time: 1000, expected: '50px' }]);
+                           [{ time: 500,  expected: '30px' }]);
     }, property + ' supports animating as a length');
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['1rem', '5rem'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px' },
-                            { time: 500,  expected: '30px' },
-                            { time: 1000, expected: '50px' }]);
+                           [{ time: 500,  expected: '30px' }]);
     }, property + ' supports animating as a length of rem');
   },
 
   testAddition: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       target.style[idlName] = '10px';
@@ -170,19 +166,17 @@ const lengthPairType = {
 const percentageType = {
   testInterpolation: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['10%', '50%'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10%' },
-                            { time: 500,  expected: '30%' },
-                            { time: 1000, expected: '50%' }]);
+                           [{ time: 500,  expected: '30%' }]);
     }, property + ' supports animating as a percentage');
   },
 
   testAddition: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       target.style[idlName] = '60%';
@@ -197,19 +191,17 @@ const percentageType = {
 const integerType = {
   testInterpolation: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: [-2, 2] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '-2' },
-                            { time: 500,  expected: '0' },
-                            { time: 1000, expected: '2' }]);
+                           [{ time: 500,  expected: '0' }]);
     }, property + ' supports animating as an integer');
   },
 
   testAddition: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       target.style[idlName] = -1;
@@ -228,67 +220,55 @@ const lengthPercentageOrCalcType = {
     percentageType.testInterpolation(property, setup);
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['10px', '20%'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px' },
-                            { time: 500,  expected: 'calc(5px + 10%)' },
-                            { time: 1000, expected: '20%' }]);
+                           [{ time: 500,  expected: 'calc(5px + 10%)' }]);
     }, property + ' supports animating as combination units "px" and "%"');
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['10%', '2em'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10%' },
-                            { time: 500,  expected: 'calc(10px + 5%)' },
-                            { time: 1000, expected: '20px' }]);
+                           [{ time: 500,  expected: 'calc(10px + 5%)' }]);
     }, property + ' supports animating as combination units "%" and "em"');
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['1em', '2rem'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px' },
-                            { time: 500,  expected: '15px' },
-                            { time: 1000, expected: '20px' }]);
+                           [{ time: 500,  expected: '15px' }]);
     }, property + ' supports animating as combination units "em" and "rem"');
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['10px', 'calc(1em + 20%)'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px' },
-                            { time: 500,  expected: 'calc(10px + 10%)' },
-                            { time: 1000, expected: 'calc(10px + 20%)' }]);
+                           [{ time: 500,  expected: 'calc(10px + 10%)' }]);
     }, property + ' supports animating as combination units "px" and "calc"');
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate(
         { [idlName]: ['calc(10px + 10%)', 'calc(1em + 1rem + 20%)'] },
         { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,
-                              expected: 'calc(10px + 10%)' },
-                            { time: 500,
-                              expected: 'calc(15px + 15%)' },
-                            { time: 1000,
-                              expected: 'calc(20px + 20%)' }]);
+                           [{ time: 500,
+                              expected: 'calc(15px + 15%)' }]);
     }, property + ' supports animating as a calc');
   },
 
   testAddition: function(property, setup) {
     lengthType.testAddition(property, setup);
     percentageType.testAddition(property, setup);
 
     test(function(t) {
@@ -377,19 +357,17 @@ const lengthPercentageOrCalcType = {
 const positiveNumberType = {
   testInterpolation: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: [1.1, 1.5] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '1.1' },
-                            { time: 500,  expected: '1.3' },
-                            { time: 1000, expected: '1.5' }]);
+                           [{ time: 500,  expected: '1.3' }]);
     }, property + ' supports animating as a positive number');
   },
 
   testAddition: function(property, setup) {
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       target.style[idlName] = 1.1;
@@ -1149,69 +1127,31 @@ const boxShadowListType = {
         [ { time: 0, expected: 'rgb(0, 0, 0) 0px 0px 0px 0px, ' +
                                'rgb(120, 120, 120) 10px 10px 10px 0px' }]);
     }, property + ': shadow');
   },
 };
 
 const positionType = {
   testInterpolation: function(property, setup) {
-    test(function(t) {
-      var idlName = propertyToIDL(property);
-      var target = createTestElement(t, setup);
-      var animation = target.animate({ [idlName]: ['10px 10px', '50px 50px'] },
-                                     { duration: 1000, fill: 'both' });
-      testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px 10px' },
-                            { time: 500,  expected: '30px 30px' },
-                            { time: 1000, expected: '50px 50px' }]);
-    }, property + ' supports animating as a position');
-
-    test(function(t) {
-      var idlName = propertyToIDL(property);
-      var target = createTestElement(t, setup);
-      var animation = target.animate({ [idlName]: ['1rem 1rem', '5rem 5rem'] },
-                                     { duration: 1000, fill: 'both' });
-      testAnimationSamples(animation, idlName,
-                           [{ time: 0,    expected: '10px 10px' },
-                            { time: 500,  expected: '30px 30px' },
-                            { time: 1000, expected: '50px 50px' }]);
-    }, property + ' supports animating as a position of rem');
+    lengthPairType.testInterpolation(property, setup);
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       var animation = target.animate({ [idlName]: ['10% 10%', '50% 50%'] },
                                      { duration: 1000, fill: 'both' });
       testAnimationSamples(
         animation, idlName,
-        [{ time: 0,    expected: calcFromPercentage(idlName, '10% 10%') },
-         { time: 500,  expected: calcFromPercentage(idlName, '30% 30%') },
-         { time: 1000, expected: calcFromPercentage(idlName, '50% 50%') }]);
+        [{ time: 500,  expected: calcFromPercentage(idlName, '30% 30%') }]);
     }, property + ' supports animating as a position of percent');
   },
 
   testAddition: function(property, setup) {
-    test(function(t) {
-      var idlName = propertyToIDL(property);
-      var target = createTestElement(t, setup);
-      target.style[idlName] = '10px 10px';
-      var animation = target.animate({ [idlName]: ['10px 10px', '50px 50px'] },
-                                     { duration: 1000, composite: 'add' });
-      testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px 20px' }]);
-    }, property + ': position');
-
-    test(function(t) {
-      var idlName = propertyToIDL(property);
-      var target = createTestElement(t, setup);
-      target.style[idlName] = '1rem 1rem';
-      var animation = target.animate({ [idlName]: ['1rem 1rem', '5rem 5rem'] },
-                                     { duration: 1000, composite: 'add' });
-      testAnimationSamples(animation, idlName, [{ time: 0, expected: '20px 20px' }]);
-    }, property + ': position of rem');
+    lengthPairType.testAddition(property, setup);
 
     test(function(t) {
       var idlName = propertyToIDL(property);
       var target = createTestElement(t, setup);
       target.style[idlName] = '60% 60%';
       var animation = target.animate({ [idlName]: ['70% 70%', '100% 100%'] },
                                      { duration: 1000, composite: 'add' });
       testAnimationSamples(
--- a/tools/profiler/core/ProfileBuffer.cpp
+++ b/tools/profiler/core/ProfileBuffer.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; 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 "ProfileBuffer.h"
 
+#include "ProfilerMarker.h"
+
 ProfileBuffer::ProfileBuffer(int aEntrySize)
   : mEntries(mozilla::MakeUnique<ProfileBufferEntry[]>(aEntrySize))
   , mWritePos(0)
   , mReadPos(0)
   , mEntrySize(aEntrySize)
   , mGeneration(0)
 {
 }
--- a/tools/profiler/core/ProfileBuffer.h
+++ b/tools/profiler/core/ProfileBuffer.h
@@ -1,18 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; 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 MOZ_PROFILE_BUFFER_H
 #define MOZ_PROFILE_BUFFER_H
 
+#include "platform.h"
 #include "ProfileBufferEntry.h"
-#include "platform.h"
+#include "ProfilerMarker.h"
 #include "ProfileJSONWriter.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/RefCounted.h"
 
 class ProfileBuffer final
 {
 public:
   explicit ProfileBuffer(int aEntrySize);
--- a/tools/profiler/core/ProfileBufferEntry.h
+++ b/tools/profiler/core/ProfileBufferEntry.h
@@ -7,30 +7,31 @@
 #ifndef ProfileBufferEntry_h
 #define ProfileBufferEntry_h
 
 #include <ostream>
 #include "GeckoProfiler.h"
 #include "platform.h"
 #include "ProfileJSONWriter.h"
 #include "ProfilerBacktrace.h"
-#include "PseudoStack.h"
 #include "mozilla/RefPtr.h"
 #include <string>
 #include <map>
 #include "js/ProfilingFrameIterator.h"
 #include "js/TrackedOptimizationInfo.h"
 #include "nsHashKeys.h"
 #include "nsDataHashtable.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Vector.h"
 #include "gtest/MozGtestFriend.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/UniquePtr.h"
 
+class ProfilerMarker;
+
 #define PROFILE_BUFFER_ENTRY_KIND_LIST(_) \
     _(Category,        int)               \
     _(CodeLocation,    const char *)      \
     _(EmbeddedString,  void *)            \
     _(JitReturnAddr,   void *)            \
     _(LineNumber,      int)               \
     _(NativeLeafAddr,  void *)            \
     _(Marker,          ProfilerMarker *)  \
new file mode 100644
--- /dev/null
+++ b/tools/profiler/core/ProfilerMarker.h
@@ -0,0 +1,177 @@
+/* -*- 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 ProfilerMarker_h
+#define ProfilerMarker_h
+
+#include "mozilla/UniquePtrExtensions.h"
+
+#include "ProfilerMarkerPayload.h"
+#include "StoreSequencer.h"
+
+template<typename T>
+class ProfilerLinkedList;
+class SpliceableJSONWriter;
+class UniqueStacks;
+
+class ProfilerMarker
+{
+  friend class ProfilerLinkedList<ProfilerMarker>;
+
+public:
+  explicit ProfilerMarker(const char* aMarkerName,
+                          ProfilerMarkerPayload* aPayload = nullptr,
+                          double aTime = 0)
+    : mMarkerName(strdup(aMarkerName))
+    , mPayload(aPayload)
+    , mTime(aTime)
+  {}
+
+  void SetGeneration(uint32_t aGenID) { mGenID = aGenID; }
+
+  bool HasExpired(uint32_t aGenID) const { return mGenID + 2 <= aGenID; }
+
+  double GetTime() const { return mTime; }
+
+  void StreamJSON(SpliceableJSONWriter& aWriter,
+                  const mozilla::TimeStamp& aStartTime,
+                  UniqueStacks& aUniqueStacks) const
+  {
+    // Schema:
+    //   [name, time, data]
+
+    aWriter.StartArrayElement();
+    {
+      aUniqueStacks.mUniqueStrings.WriteElement(aWriter, mMarkerName.get());
+      aWriter.DoubleElement(mTime);
+      // TODO: Store the callsite for this marker if available:
+      // if have location data
+      //   b.NameValue(marker, "location", ...);
+      if (mPayload) {
+        aWriter.StartObjectElement();
+        {
+          mPayload->StreamPayload(aWriter, aStartTime, aUniqueStacks);
+        }
+        aWriter.EndObject();
+      }
+    }
+    aWriter.EndArray();
+  }
+
+private:
+  mozilla::UniqueFreePtr<char> mMarkerName;
+  mozilla::UniquePtr<ProfilerMarkerPayload> mPayload;
+  ProfilerMarker* mNext;
+  double mTime;
+  uint32_t mGenID;
+};
+
+template<typename T>
+class ProfilerLinkedList
+{
+public:
+  ProfilerLinkedList()
+    : mHead(nullptr)
+    , mTail(nullptr)
+  {}
+
+  void insert(T* aElem)
+  {
+    if (!mTail) {
+      mHead = aElem;
+      mTail = aElem;
+    } else {
+      mTail->mNext = aElem;
+      mTail = aElem;
+    }
+    aElem->mNext = nullptr;
+  }
+
+  T* popHead()
+  {
+    if (!mHead) {
+      MOZ_ASSERT(false);
+      return nullptr;
+    }
+
+    T* head = mHead;
+
+    mHead = head->mNext;
+    if (!mHead) {
+      mTail = nullptr;
+    }
+
+    return head;
+  }
+
+  const T* peek() {
+    return mHead;
+  }
+
+private:
+  T* mHead;
+  T* mTail;
+};
+
+typedef ProfilerLinkedList<ProfilerMarker> ProfilerMarkerLinkedList;
+
+template<typename T>
+class ProfilerSignalSafeLinkedList
+{
+public:
+  ProfilerSignalSafeLinkedList()
+    : mSignalLock(false)
+  {}
+
+  ~ProfilerSignalSafeLinkedList()
+  {
+    if (mSignalLock) {
+      // Some thread is modifying the list. We should only be released on that
+      // thread.
+      abort();
+    }
+
+    while (mList.peek()) {
+      delete mList.popHead();
+    }
+  }
+
+  // Insert an item into the list. Must only be called from the owning thread.
+  // Must not be called while the list from accessList() is being accessed.
+  // In the profiler, we ensure that by interrupting the profiled thread
+  // (which is the one that owns this list and calls insert() on it) until
+  // we're done reading the list from the signal handler.
+  void insert(T* aElement)
+  {
+    MOZ_ASSERT(aElement);
+
+    mSignalLock = true;
+    STORE_SEQUENCER();
+
+    mList.insert(aElement);
+
+    STORE_SEQUENCER();
+    mSignalLock = false;
+  }
+
+  // Called within signal, from any thread, possibly while insert() is in the
+  // middle of modifying the list (on the owning thread). Will return null if
+  // that is the case.
+  // Function must be reentrant.
+  ProfilerLinkedList<T>* accessList()
+  {
+    return mSignalLock ? nullptr : &mList;
+  }
+
+private:
+  ProfilerLinkedList<T> mList;
+
+  // If this is set, then it's not safe to read the list because its contents
+  // are being changed.
+  volatile bool mSignalLock;
+};
+
+#endif  // ProfilerMarker_h
rename from tools/profiler/core/ProfilerMarkers.cpp
rename to tools/profiler/core/ProfilerMarkerPayload.cpp
--- a/tools/profiler/core/ProfilerMarkers.cpp
+++ b/tools/profiler/core/ProfilerMarkerPayload.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; 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 "GeckoProfiler.h"
 #include "ProfilerBacktrace.h"
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #include "gfxASurface.h"
 #include "Layers.h"
 #include "mozilla/Sprintf.h"
 
 ProfilerMarkerPayload::ProfilerMarkerPayload(UniqueProfilerBacktrace aStack)
   : mStack(mozilla::Move(aStack))
 {}
 
--- a/tools/profiler/core/ThreadInfo.h
+++ b/tools/profiler/core/ThreadInfo.h
@@ -5,18 +5,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ThreadInfo_h
 #define ThreadInfo_h
 
 #include "mozilla/NotNull.h"
 #include "mozilla/UniquePtrExtensions.h"
 
+#include "platform.h"
 #include "ProfileBuffer.h"
-#include "platform.h"
+#include "PseudoStack.h"
 
 // Stub eventMarker function for js-engine event generation.
 void ProfilerJSEventMarker(const char* aEvent);
 
 // This class contains the info for a single thread that is accessible without
 // protection from gPSMutex in platform.cpp. Because there is no external
 // protection against data races, it must provide internal protection. Hence
 // the "Racy" prefix.
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -32,17 +32,17 @@
 #include "nsIXULRuntime.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsMemoryReporterManager.h"
 #include "nsXULAppAPI.h"
 #include "nsProfilerStartParams.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #include "shared-libraries.h"
 #include "prtime.h"
 
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #endif
 
 #if defined(PROFILE_JAVA)
@@ -1573,18 +1573,16 @@ locked_profiler_stream_json_for_this_pro
     aWriter.StartObjectProperty("tasktracer");
     StreamTaskTracer(aLock, aWriter);
     aWriter.EndObject();
   }
 
   // Lists the samples for each thread profile
   aWriter.StartArrayProperty("threads");
   {
-    ActivePS::SetIsPaused(aLock, true);
-
     const CorePS::ThreadVector& liveThreads = CorePS::LiveThreads(aLock);
     for (size_t i = 0; i < liveThreads.size(); i++) {
       ThreadInfo* info = liveThreads.at(i);
       if (!info->IsBeingProfiled()) {
         continue;
       }
       info->StreamJSON(ActivePS::Buffer(aLock), aWriter,
                        CorePS::ProcessStartTime(aLock), aSinceTime);
@@ -1606,18 +1604,16 @@ locked_profiler_stream_json_for_this_pro
       {
         BuildJavaThreadJSObject(aWriter);
       }
       aWriter.End();
 
       java::GeckoJavaSampler::Unpause();
     }
 #endif
-
-    ActivePS::SetIsPaused(aLock, false);
   }
   aWriter.EndArray();
 }
 
 bool
 profiler_stream_json_for_this_process(SpliceableJSONWriter& aWriter, double aSinceTime)
 {
   LOG("profiler_stream_json_for_this_process");
@@ -1633,65 +1629,16 @@ profiler_stream_json_for_this_process(Sp
 
   locked_profiler_stream_json_for_this_process(lock, aWriter, aSinceTime);
   return true;
 }
 
 // END saving/streaming code
 ////////////////////////////////////////////////////////////////////////
 
-ProfilerMarker::ProfilerMarker(const char* aMarkerName,
-                               ProfilerMarkerPayload* aPayload,
-                               double aTime)
-  : mMarkerName(strdup(aMarkerName))
-  , mPayload(aPayload)
-  , mTime(aTime)
-{
-}
-
-ProfilerMarker::~ProfilerMarker() {
-  free(mMarkerName);
-  delete mPayload;
-}
-
-void
-ProfilerMarker::SetGeneration(uint32_t aGenID) {
-  mGenID = aGenID;
-}
-
-double
-ProfilerMarker::GetTime() const {
-  return mTime;
-}
-
-void ProfilerMarker::StreamJSON(SpliceableJSONWriter& aWriter,
-                                const TimeStamp& aProcessStartTime,
-                                UniqueStacks& aUniqueStacks) const
-{
-  // Schema:
-  //   [name, time, data]
-
-  aWriter.StartArrayElement();
-  {
-    aUniqueStacks.mUniqueStrings.WriteElement(aWriter, GetMarkerName());
-    aWriter.DoubleElement(mTime);
-    // TODO: Store the callsite for this marker if available:
-    // if have location data
-    //   b.NameValue(marker, "location", ...);
-    if (mPayload) {
-      aWriter.StartObjectElement();
-      {
-        mPayload->StreamPayload(aWriter, aProcessStartTime, aUniqueStacks);
-      }
-      aWriter.EndObject();
-    }
-  }
-  aWriter.EndArray();
-}
-
 static void
 PrintUsageThenExit(int aExitCode)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   printf(
     "\n"
     "Profiler environment variable usage:\n"
@@ -3065,25 +3012,21 @@ profiler_clear_js_context()
   if (!info || !info->mContext) {
     return;
   }
 
   // On JS shut down, flush the current buffer as stringifying JIT samples
   // requires a live JSContext.
 
   if (ActivePS::Exists(lock)) {
-    ActivePS::SetIsPaused(lock, true);
-
     // Flush this thread's ThreadInfo, if it is being profiled.
     if (info->IsBeingProfiled()) {
       info->FlushSamplesAndMarkers(ActivePS::Buffer(lock),
                                    CorePS::ProcessStartTime(lock));
     }
-
-    ActivePS::SetIsPaused(lock, false);
   }
 
   // We don't call info->StopJSSampling() here; there's no point doing that for
   // a JS thread that is in the process of disappearing.
 
   info->mContext = nullptr;
 }
 
--- a/tools/profiler/gecko/ProfilerIOInterposeObserver.cpp
+++ b/tools/profiler/gecko/ProfilerIOInterposeObserver.cpp
@@ -1,15 +1,15 @@
 /* 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 "GeckoProfiler.h"
 #include "ProfilerIOInterposeObserver.h"
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 
 using namespace mozilla;
 
 void ProfilerIOInterposeObserver::Observe(Observation& aObservation)
 {
   if (!IsMainThread()) {
     return;
   }
--- a/tools/profiler/moz.build
+++ b/tools/profiler/moz.build
@@ -6,30 +6,31 @@
 
 if CONFIG['MOZ_GECKO_PROFILER']:
     XPIDL_MODULE = 'profiler'
     XPIDL_SOURCES += [
         'gecko/nsIProfiler.idl',
     ]
     EXPORTS += [
         'public/CrossProcessProfilerController.h',
-        'public/ProfilerMarkers.h',
+        'public/ProfilerMarkerPayload.h',
         'public/PseudoStack.h',
         'public/shared-libraries.h',
+        'public/StoreSequencer.h',
     ]
     EXTRA_JS_MODULES += [
         'gecko/Profiler.jsm',
     ]
     UNIFIED_SOURCES += [
         'core/platform.cpp',
         'core/ProfileBuffer.cpp',
         'core/ProfileBufferEntry.cpp',
         'core/ProfileJSONWriter.cpp',
         'core/ProfilerBacktrace.cpp',
-        'core/ProfilerMarkers.cpp',
+        'core/ProfilerMarkerPayload.cpp',
         'core/StackTop.cpp',
         'core/ThreadInfo.cpp',
         'gecko/CrossProcessProfilerController.cpp',
         'gecko/nsProfilerFactory.cpp',
         'gecko/nsProfilerStartParams.cpp',
         'gecko/ProfileGatherer.cpp',
         'gecko/ProfilerIOInterposeObserver.cpp',
         'gecko/ThreadResponsiveness.cpp',
rename from tools/profiler/public/ProfilerMarkers.h
rename to tools/profiler/public/ProfilerMarkerPayload.h
--- a/tools/profiler/public/PseudoStack.h
+++ b/tools/profiler/public/PseudoStack.h
@@ -4,195 +4,23 @@
  * 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 PseudoStack_h
 #define PseudoStack_h
 
 #include "mozilla/ArrayUtils.h"
 #include "js/ProfilingStack.h"
-#include "nsISupportsImpl.h"
+#include "StoreSequencer.h"
 
 #include <stdlib.h>
 #include <stdint.h>
 
 #include <algorithm>
 
-// STORE_SEQUENCER: Because signals can interrupt our profile modification
-//                  we need to make stores are not re-ordered by the compiler
-//                  or hardware to make sure the profile is consistent at
-//                  every point the signal can fire.
-#if defined(__arm__)
-// TODO Is there something cheaper that will prevent memory stores from being
-// reordered?
-
-typedef void (*LinuxKernelMemoryBarrierFunc)(void);
-LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
-    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
-
-# define STORE_SEQUENCER() pLinuxKernelMemoryBarrier()
-
-#elif defined(__i386__) || defined(__x86_64__) || \
-      defined(_M_IX86) || defined(_M_X64)
-# if defined(_MSC_VER)
-#  include <intrin.h>
-#  define STORE_SEQUENCER() _ReadWriteBarrier();
-# elif defined(__INTEL_COMPILER)
-#  define STORE_SEQUENCER() __memory_barrier();
-# elif __GNUC__
-#  define STORE_SEQUENCER() asm volatile("" ::: "memory");
-# else
-#  error "Memory clobber not supported for your compiler."
-# endif
-
-#else
-# error "Memory clobber not supported for your platform."
-#endif
-
-class ProfilerMarkerPayload;
-template<typename T>
-class ProfilerLinkedList;
-class SpliceableJSONWriter;
-class UniqueStacks;
-
-class ProfilerMarker
-{
-  friend class ProfilerLinkedList<ProfilerMarker>;
-
-public:
-  explicit ProfilerMarker(const char* aMarkerName,
-                          ProfilerMarkerPayload* aPayload = nullptr,
-                          double aTime = 0);
-  ~ProfilerMarker();
-
-  const char* GetMarkerName() const { return mMarkerName; }
-
-  void StreamJSON(SpliceableJSONWriter& aWriter,
-                  const mozilla::TimeStamp& aStartTime,
-                  UniqueStacks& aUniqueStacks) const;
-
-  void SetGeneration(uint32_t aGenID);
-
-  bool HasExpired(uint32_t aGenID) const { return mGenID + 2 <= aGenID; }
-
-  double GetTime() const;
-
-private:
-  char* mMarkerName;
-  ProfilerMarkerPayload* mPayload;
-  ProfilerMarker* mNext;
-  double mTime;
-  uint32_t mGenID;
-};
-
-template<typename T>
-class ProfilerLinkedList
-{
-public:
-  ProfilerLinkedList()
-    : mHead(nullptr)
-    , mTail(nullptr)
-  {}
-
-  void insert(T* aElem)
-  {
-    if (!mTail) {
-      mHead = aElem;
-      mTail = aElem;
-    } else {
-      mTail->mNext = aElem;
-      mTail = aElem;
-    }
-    aElem->mNext = nullptr;
-  }
-
-  T* popHead()
-  {
-    if (!mHead) {
-      MOZ_ASSERT(false);
-      return nullptr;
-    }
-
-    T* head = mHead;
-
-    mHead = head->mNext;
-    if (!mHead) {
-      mTail = nullptr;
-    }
-
-    return head;
-  }
-
-  const T* peek() {
-    return mHead;
-  }
-
-private:
-  T* mHead;
-  T* mTail;
-};
-
-typedef ProfilerLinkedList<ProfilerMarker> ProfilerMarkerLinkedList;
-
-template<typename T>
-class ProfilerSignalSafeLinkedList
-{
-public:
-  ProfilerSignalSafeLinkedList()
-    : mSignalLock(false)
-  {}
-
-  ~ProfilerSignalSafeLinkedList()
-  {
-    if (mSignalLock) {
-      // Some thread is modifying the list. We should only be released on that
-      // thread.
-      abort();
-    }
-
-    while (mList.peek()) {
-      delete mList.popHead();
-    }
-  }
-
-  // Insert an item into the list. Must only be called from the owning thread.
-  // Must not be called while the list from accessList() is being accessed.
-  // In the profiler, we ensure that by interrupting the profiled thread
-  // (which is the one that owns this list and calls insert() on it) until
-  // we're done reading the list from the signal handler.
-  void insert(T* aElement)
-  {
-    MOZ_ASSERT(aElement);
-
-    mSignalLock = true;
-    STORE_SEQUENCER();
-
-    mList.insert(aElement);
-
-    STORE_SEQUENCER();
-    mSignalLock = false;
-  }
-
-  // Called within signal, from any thread, possibly while insert() is in the
-  // middle of modifying the list (on the owning thread). Will return null if
-  // that is the case.
-  // Function must be reentrant.
-  ProfilerLinkedList<T>* accessList()
-  {
-    return mSignalLock ? nullptr : &mList;
-  }
-
-private:
-  ProfilerLinkedList<T> mList;
-
-  // If this is set, then it's not safe to read the list because its contents
-  // are being changed.
-  volatile bool mSignalLock;
-};
-
 // The PseudoStack members are read by signal handlers, so the mutation of them
 // needs to be signal-safe.
 class PseudoStack
 {
 public:
   PseudoStack()
     : mStackPointer(0)
   {
new file mode 100644
--- /dev/null
+++ b/tools/profiler/public/StoreSequencer.h
@@ -0,0 +1,41 @@
+/* -*- 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 StoreSequencer_h
+#define StoreSequencer_h
+
+// STORE_SEQUENCER is a memory barrier used to ensure profiles are updated
+// safely.
+
+#if defined(__arm__)
+// TODO Is there something cheaper that will prevent memory stores from being
+// reordered?
+
+typedef void (*LinuxKernelMemoryBarrierFunc)(void);
+LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
+    (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
+
+# define STORE_SEQUENCER() pLinuxKernelMemoryBarrier()
+
+#elif defined(__i386__) || defined(__x86_64__) || \
+      defined(_M_IX86) || defined(_M_X64)
+
+# if defined(_MSC_VER)
+#  include <intrin.h>
+#  define STORE_SEQUENCER() _ReadWriteBarrier();
+# elif defined(__INTEL_COMPILER)
+#  define STORE_SEQUENCER() __memory_barrier();
+# elif __GNUC__
+#  define STORE_SEQUENCER() asm volatile("" ::: "memory");
+# else
+#  error "STORE_SEQUENCER not supported for your compiler."
+# endif
+
+#else
+# error "STORE_SEQUENCER not supported for your platform."
+#endif
+
+#endif  // StoreSequencer_h
--- a/tools/profiler/tests/gtest/GeckoProfiler.cpp
+++ b/tools/profiler/tests/gtest/GeckoProfiler.cpp
@@ -7,17 +7,17 @@
 // This file tests a lot of the profiler_*() functions in GeckoProfiler.h.
 // Most of the tests just check that nothing untoward (e.g. crashes, deadlocks)
 // happens when calling these functions. They don't do much inspection of
 // profiler internals.
 
 #include "gtest/gtest.h"
 
 #include "GeckoProfiler.h"
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #include "jsapi.h"
 #include "js/Initialization.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "ProfileJSONWriter.h"
 
 #include <string.h>
 
 // Note: profiler_init() has already been called in XRE_main(), so we can't
--- a/widget/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -8,17 +8,17 @@
 #include "VsyncSource.h"
 #include "gfxPlatform.h"
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 
 #ifdef MOZ_GECKO_PROFILER
 #include "GeckoProfiler.h"
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #endif
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 
 CompositorVsyncDispatcher::CompositorVsyncDispatcher()
   : mCompositorObserverLock("CompositorObserverLock")
--- a/widget/gonk/GeckoTouchDispatcher.cpp
+++ b/widget/gonk/GeckoTouchDispatcher.cpp
@@ -14,17 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "FrameMetrics.h"
 #include "GeckoProfiler.h"
 #include "GeckoTouchDispatcher.h"
 #include "InputData.h"
-#include "ProfilerMarkers.h"
+#include "ProfilerMarkerPayload.h"
 #include "base/basictypes.h"
 #include "gfxPrefs.h"
 #include "libui/Input.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 #include "mozilla/dom/Touch.h"
@@ -345,14 +345,16 @@ GeckoTouchDispatcher::DispatchTouchEvent
         touchAction = "Touch_Event_Up";
         break;
       case MultiTouchInput::MULTITOUCH_SENTINEL:
         MOZ_ASSERT_UNREACHABLE("Invalid MultTouchInput.");
         break;
     }
 
     const ScreenIntPoint& touchPoint = aMultiTouch.mTouches[0].mScreenPoint;
+#ifdef MOZ_GECKO_PROFILER
     TouchDataPayload* payload = new TouchDataPayload(touchPoint);
     PROFILER_MARKER_PAYLOAD(touchAction, payload);
+#endif
   }
 }
 
 } // namespace mozilla