Add MLGPU feature bits and compositor initialization. (bug 1365879 part 21, r=mattwoodrow)
☠☠ backed out by 120d49a127d6 ☠ ☠
authorDavid Anderson <danderson@mozilla.com>
Thu, 22 Jun 2017 21:12:19 -0700
changeset 416857 9d0048e044465ca3c1ba1dded202df3b091b79f6
parent 416856 8069471cda21110700b5a451641f3e2faed95418
child 416858 be62d3eb3b3b125a4421277a8819c8b192416c23
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1365879
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Add MLGPU feature bits and compositor initialization. (bug 1365879 part 21, r=mattwoodrow)
gfx/config/gfxFeature.h
gfx/ipc/CompositorOptions.h
gfx/ipc/GPUChild.cpp
gfx/ipc/GPUChild.h
gfx/ipc/GPUParent.cpp
gfx/ipc/GfxMessageUtils.h
gfx/ipc/GraphicsMessages.ipdlh
gfx/ipc/PGPU.ipdl
gfx/layers/d3d11/MLGDeviceD3D11.cpp
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/LayersMessageUtils.h
gfx/layers/mlgpu/LayerManagerMLGPU.cpp
gfx/layers/mlgpu/MLGDevice.h
gfx/thebes/DeviceManagerDx.cpp
gfx/thebes/DeviceManagerDx.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPrefs.h
gfx/thebes/gfxWindowsPlatform.cpp
widget/nsBaseWidget.cpp
--- a/gfx/config/gfxFeature.h
+++ b/gfx/config/gfxFeature.h
@@ -21,16 +21,17 @@ namespace gfx {
   _(D3D11_COMPOSITING,            Feature,      "Direct3D11 Compositing")         \
   _(OPENGL_COMPOSITING,           Feature,      "OpenGL Compositing")             \
   _(DIRECT2D,                     Feature,      "Direct2D")                       \
   _(D3D11_HW_ANGLE,               Feature,      "Direct3D11 hardware ANGLE")      \
   _(DIRECT_DRAW,                  Feature,      "DirectDraw")                     \
   _(GPU_PROCESS,                  Feature,      "GPU Process")                    \
   _(WEBRENDER,                    Feature,      "WebRender")                      \
   _(OMTP,                         Feature,      "Off Main Thread Painting")       \
+  _(ADVANCED_LAYERS,              Feature,      "Advanced Layers")                \
   /* Add new entries above this comment */
 
 enum class Feature : uint32_t {
 #define MAKE_ENUM(name, type, desc) name,
   GFX_FEATURE_MAP(MAKE_ENUM)
 #undef MAKE_ENUM
   NumValues
 };
--- a/gfx/ipc/CompositorOptions.h
+++ b/gfx/ipc/CompositorOptions.h
@@ -27,39 +27,47 @@ namespace layers {
  */
 class CompositorOptions
 {
 public:
   // This constructor needed for IPDL purposes, don't use it anywhere else.
   CompositorOptions()
     : mUseAPZ(false)
     , mUseWebRender(false)
+    , mUseAdvancedLayers(false)
   {
   }
 
   explicit CompositorOptions(bool aUseAPZ,
                              bool aUseWebRender)
     : mUseAPZ(aUseAPZ)
     , mUseWebRender(aUseWebRender)
+    , mUseAdvancedLayers(false)
   {
   }
 
   bool UseAPZ() const { return mUseAPZ; }
   bool UseWebRender() const { return mUseWebRender; }
+  bool UseAdvancedLayers() const { return mUseAdvancedLayers; }
+
+  void SetUseAdvancedLayers(bool aUseAdvancedLayers) {
+    mUseAdvancedLayers = aUseAdvancedLayers;
+  }
 
   bool operator==(const CompositorOptions& aOther) const {
     return mUseAPZ == aOther.mUseAPZ &&
            mUseWebRender == aOther.mUseWebRender;
   }
 
   friend struct IPC::ParamTraits<CompositorOptions>;
 
 private:
   bool mUseAPZ;
   bool mUseWebRender;
+  bool mUseAdvancedLayers;
 
   // Make sure to add new fields to the ParamTraits implementation
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // _include_mozilla_gfx_ipc_CompositorOptions_h_
--- a/gfx/ipc/GPUChild.cpp
+++ b/gfx/ipc/GPUChild.cpp
@@ -62,16 +62,17 @@ GPUChild::Init()
   }
 
   nsTArray<GfxVarUpdate> updates = gfxVars::FetchNonDefaultVars();
 
   DevicePrefs devicePrefs;
   devicePrefs.hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
   devicePrefs.d3d11Compositing() = gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
   devicePrefs.oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
+  devicePrefs.advancedLayers() = gfxConfig::GetValue(Feature::ADVANCED_LAYERS);
   devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
 
   nsTArray<LayerTreeIdMapping> mappings;
   LayerTreeOwnerTracker::Get()->Iterate([&](uint64_t aLayersId, base::ProcessId aProcessId) {
     mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
   });
 
   SendInit(prefs, updates, devicePrefs, mappings);
@@ -267,16 +268,23 @@ GPUChild::ActorDestroy(ActorDestroyReaso
     }
 
   }
 
   gfxVars::RemoveReceiver(this);
   mHost->OnChannelClosed();
 }
 
+mozilla::ipc::IPCResult
+GPUChild::RecvUpdateFeature(const Feature& aFeature, const FeatureFailure& aChange)
+{
+  gfxConfig::SetFailed(aFeature, aChange.status(), aChange.message().get(), aChange.failureId());
+  return IPC_OK();
+}
+
 class DeferredDeleteGPUChild : public Runnable
 {
 public:
   explicit DeferredDeleteGPUChild(UniquePtr<GPUChild>&& aChild)
     : mChild(Move(aChild))
   {
   }
 
--- a/gfx/ipc/GPUChild.h
+++ b/gfx/ipc/GPUChild.h
@@ -53,16 +53,17 @@ public:
   mozilla::ipc::IPCResult RecvRecordDiscardedData(const DiscardedData& aDiscardedData) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override;
   mozilla::ipc::IPCResult RecvNotifyUiObservers(const nsCString& aTopic) override;
   mozilla::ipc::IPCResult RecvNotifyDeviceReset(const GPUDeviceData& aData) override;
   mozilla::ipc::IPCResult RecvAddMemoryReport(const MemoryReport& aReport) override;
   mozilla::ipc::IPCResult RecvFinishMemoryReport(const uint32_t& aGeneration) override;
+  mozilla::ipc::IPCResult RecvUpdateFeature(const Feature& aFeature, const FeatureFailure& aChange) override;
 
   bool SendRequestMemoryReport(const uint32_t& aGeneration,
                                const bool& aAnonymize,
                                const bool& aMinimizeMemoryUsage,
                                const MaybeFileDesc& aDMDFile);
 
   static void Destroy(UniquePtr<GPUChild>&& aChild);
 
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -163,16 +163,17 @@ GPUParent::RecvInit(nsTArray<GfxPrefSett
   for (const auto& var : vars) {
     gfxVars::ApplyUpdate(var);
   }
 
   // Inherit device preferences.
   gfxConfig::Inherit(Feature::HW_COMPOSITING, devicePrefs.hwCompositing());
   gfxConfig::Inherit(Feature::D3D11_COMPOSITING, devicePrefs.d3d11Compositing());
   gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, devicePrefs.oglCompositing());
+  gfxConfig::Inherit(Feature::ADVANCED_LAYERS, devicePrefs.advancedLayers());
   gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
 
   for (const LayerTreeIdMapping& map : aMappings) {
     LayerTreeOwnerTracker::Get()->Map(map.layersId(), map.ownerId());
   }
 
 #if defined(XP_WIN)
   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
@@ -295,16 +296,17 @@ CopyFeatureChange(Feature aFeature, Feat
   *aOut = FeatureFailure(feature.GetValue(), message, feature.GetFailureId());
 }
 
 mozilla::ipc::IPCResult
 GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut)
 {
   CopyFeatureChange(Feature::D3D11_COMPOSITING, &aOut->d3d11Compositing());
   CopyFeatureChange(Feature::OPENGL_COMPOSITING, &aOut->oglCompositing());
+  CopyFeatureChange(Feature::ADVANCED_LAYERS, &aOut->advancedLayers());
 
 #if defined(XP_WIN)
   if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
     D3D11DeviceStatus deviceStatus;
     dm->ExportDeviceInfo(&deviceStatus);
     aOut->gpuDevice() = deviceStatus;
   }
 #else
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -8,16 +8,17 @@
 #define __GFXMESSAGEUTILS_H__
 
 #include "FilterSupport.h"
 #include "FrameMetrics.h"
 #include "ImageTypes.h"
 #include "RegionBuilder.h"
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
+#include "gfxFeature.h"
 #include "gfxPoint.h"
 #include "gfxRect.h"
 #include "gfxTelemetry.h"
 #include "gfxTypes.h"
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/gfx/Matrix.h"
 #include "nsRect.h"
 #include "nsRegion.h"
@@ -215,16 +216,24 @@ template <>
 struct ParamTraits<mozilla::gfx::BackendType>
   : public ContiguousEnumSerializer<
              mozilla::gfx::BackendType,
              mozilla::gfx::BackendType::NONE,
              mozilla::gfx::BackendType::BACKEND_LAST>
 {};
 
 template <>
+struct ParamTraits<mozilla::gfx::Feature>
+  : public ContiguousEnumSerializer<
+             mozilla::gfx::Feature,
+             mozilla::gfx::Feature::HW_COMPOSITING,
+             mozilla::gfx::Feature::NumValues>
+{};
+
+template <>
 struct ParamTraits<mozilla::gfx::FeatureStatus>
   : public ContiguousEnumSerializer<
              mozilla::gfx::FeatureStatus,
              mozilla::gfx::FeatureStatus::Unused,
              mozilla::gfx::FeatureStatus::LAST>
 {};
 
 template <>
@@ -899,11 +908,12 @@ struct ParamTraits<mozilla::Array<T, Len
       if (!ReadParam<T>(aMsg, aIter, &aResult->operator[](i))) {
         return false;
       }
     }
     return true;
   }
 };
 
+
 } /* namespace IPC */
 
 #endif /* __GFXMESSAGEUTILS_H__ */
--- a/gfx/ipc/GraphicsMessages.ipdlh
+++ b/gfx/ipc/GraphicsMessages.ipdlh
@@ -23,16 +23,17 @@ struct D3D11DeviceStatus
   DxgiAdapterDesc adapter;
 };
 
 struct DevicePrefs
 {
   FeatureStatus hwCompositing;
   FeatureStatus d3d11Compositing;
   FeatureStatus oglCompositing;
+  FeatureStatus advancedLayers;
   FeatureStatus useD2D1;
 };
 
 struct ContentDeviceData
 {
   DevicePrefs prefs;
   D3D11DeviceStatus d3d11;
 };
@@ -58,16 +59,17 @@ union GPUDeviceStatus
   null_t;
   D3D11DeviceStatus;
 };
 
 struct GPUDeviceData
 {
   FeatureChange d3d11Compositing;
   FeatureChange oglCompositing;
+  FeatureChange advancedLayers;
   GPUDeviceStatus gpuDevice;
 };
 
 union GfxVarValue
 {
   BackendType;
   bool;
   gfxImageFormat;
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -16,16 +16,17 @@ include protocol PVideoDecoderManager;
 using base::ProcessId from "base/process.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::ScalarAction from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::KeyedScalarAction from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::ChildEventData from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::DiscardedData from "mozilla/TelemetryComms.h";
+using mozilla::gfx::Feature from "gfxFeature.h";
 
 namespace mozilla {
 namespace gfx {
 
 union GfxPrefValue {
   bool;
   int32_t;
   uint32_t;
@@ -110,12 +111,16 @@ child:
   async UpdateChildKeyedScalars(KeyedScalarAction[] actions);
   async RecordChildEvents(ChildEventData[] events);
   async RecordDiscardedData(DiscardedData data);
 
   async NotifyDeviceReset(GPUDeviceData status);
 
   async AddMemoryReport(MemoryReport aReport);
   async FinishMemoryReport(uint32_t aGeneration);
+
+  // Update the UI process after a feature's status has changed. This is used
+  // outside of the normal startup flow.
+  async UpdateFeature(Feature aFeature, FeatureFailure aChange);
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/layers/d3d11/MLGDeviceD3D11.cpp
+++ b/gfx/layers/d3d11/MLGDeviceD3D11.cpp
@@ -715,18 +715,18 @@ MLGTextureD3D11::GetShaderResourceView()
       gfxWarning() << "Could not create shader resource view: " << hexa(hr);
       return nullptr;
     }
   }
   return mView;
 }
 
 MLGDeviceD3D11::MLGDeviceD3D11(ID3D11Device* aDevice)
- : mDevice(aDevice)
- , mScissored(false)
+ : mDevice(aDevice),
+   mScissored(false)
 {
 }
 
 MLGDeviceD3D11::~MLGDeviceD3D11()
 {
   // Caller should have unlocked all textures after presenting.
   MOZ_ASSERT(mLockedTextures.IsEmpty());
   MOZ_ASSERT(mLockAttemptedTextures.IsEmpty());
@@ -953,16 +953,17 @@ MLGDeviceD3D11::Initialize()
       !InitBlendStates() ||
       !InitSamplerStates() ||
       !InitSyncObject())
   {
     return false;
   }
 
   mCtx->RSSetState(mRasterizerStateNoScissor);
+
   return MLGDevice::Initialize();
 }
 
 bool
 MLGDeviceD3D11::InitPixelShader(PixelShaderID aShaderID)
 {
   const ShaderBytes* code = mLazyPixelShaders[aShaderID];
   HRESULT hr = mDevice->CreatePixelShader(
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -46,16 +46,17 @@
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/CompositorVsyncScheduler.h"
 #include "mozilla/layers/CrossProcessCompositorBridgeParent.h"
 #include "mozilla/layers/FrameUniformityData.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
+#include "mozilla/layers/LayerManagerMLGPU.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/layers/RemoteContentController.h"
 #include "mozilla/layers/WebRenderBridgeParent.h"
 #include "mozilla/layers/WebRenderCompositableHolder.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/webrender/WebRenderAPI.h"
@@ -88,16 +89,19 @@
 #include "mozilla/VsyncDispatcher.h"
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
 #include "VsyncSource.h"
 #endif
 #include "mozilla/widget/CompositorWidget.h"
 #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING
 # include "mozilla/widget/CompositorWidgetParent.h"
 #endif
+#ifdef XP_WIN
+# include "mozilla/gfx/DeviceManagerDx.h"
+#endif
 
 #include "LayerScope.h"
 
 namespace mozilla {
 
 namespace layers {
 
 using namespace mozilla::ipc;
@@ -1366,28 +1370,53 @@ CompositorBridgeParent::SetConfirmedTarg
 }
 
 void
 CompositorBridgeParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
 {
   NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
   NS_ASSERTION(!mCompositor,   "Already initialised mCompositor");
 
-  mCompositor = NewCompositor(aBackendHints);
-  if (!mCompositor) {
-    return;
+  if (!InitializeAdvancedLayers(aBackendHints, nullptr)) {
+    mCompositor = NewCompositor(aBackendHints);
+    if (!mCompositor) {
+      return;
+    }
+    mLayerManager = new LayerManagerComposite(mCompositor);
   }
-
-  mLayerManager = new LayerManagerComposite(mCompositor);
   mLayerManager->SetCompositorBridgeID(mCompositorBridgeID);
 
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = mLayerManager;
 }
 
+bool
+CompositorBridgeParent::InitializeAdvancedLayers(const nsTArray<LayersBackend>& aBackendHints,
+                                                 TextureFactoryIdentifier* aOutIdentifier)
+{
+#ifdef XP_WIN
+  if (!mOptions.UseAdvancedLayers()) {
+    return false;
+  }
+
+  RefPtr<LayerManagerMLGPU> manager = new LayerManagerMLGPU(mWidget);
+  if (!manager->Initialize()) {
+    return false;
+  }
+
+  if (aOutIdentifier) {
+    *aOutIdentifier = manager->GetTextureFactoryIdentifier();
+  }
+  mLayerManager = manager;
+  return true;
+#else
+  return false;
+#endif
+}
+
 RefPtr<Compositor>
 CompositorBridgeParent::NewCompositor(const nsTArray<LayersBackend>& aBackendHints)
 {
   for (size_t i = 0; i < aBackendHints.Length(); ++i) {
     RefPtr<Compositor> compositor;
     if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) {
       compositor = new CompositorOGL(this,
                                      mWidget,
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -520,16 +520,18 @@ protected:
   void ForceComposition();
   void CancelCurrentCompositeTask();
 
   // CompositorVsyncSchedulerOwner
   bool IsPendingComposite() override;
   void FinishPendingComposite() override;
   void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
 
+  bool InitializeAdvancedLayers(const nsTArray<LayersBackend>& aBackendHints,
+                                TextureFactoryIdentifier* aOutIdentifier);
   RefPtr<Compositor> NewCompositor(const nsTArray<LayersBackend>& aBackendHints);
 
   /**
    * Add a compositor to the global compositor map.
    */
   static void AddCompositor(CompositorBridgeParent* compositor, uint64_t* id);
   /**
    * Remove a compositor from the global compositor map.
--- a/gfx/layers/ipc/LayersMessageUtils.h
+++ b/gfx/layers/ipc/LayersMessageUtils.h
@@ -469,21 +469,23 @@ struct ParamTraits<mozilla::layers::Asyn
 template <>
 struct ParamTraits<mozilla::layers::CompositorOptions>
 {
   typedef mozilla::layers::CompositorOptions paramType;
 
   static void Write(Message* aMsg, const paramType& aParam) {
     WriteParam(aMsg, aParam.mUseAPZ);
     WriteParam(aMsg, aParam.mUseWebRender);
+    WriteParam(aMsg, aParam.mUseAdvancedLayers);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) {
     return ReadParam(aMsg, aIter, &aResult->mUseAPZ)
-        && ReadParam(aMsg, aIter, &aResult->mUseWebRender);
+        && ReadParam(aMsg, aIter, &aResult->mUseWebRender)
+        && ReadParam(aMsg, aIter, &aResult->mUseAdvancedLayers);
   }
 };
 
 template <>
 struct ParamTraits<mozilla::layers::SimpleLayerAttributes>
   : public PlainOldDataSerializer<mozilla::layers::SimpleLayerAttributes>
 { };
 
--- a/gfx/layers/mlgpu/LayerManagerMLGPU.cpp
+++ b/gfx/layers/mlgpu/LayerManagerMLGPU.cpp
@@ -45,17 +45,20 @@ LayerManagerMLGPU::LayerManagerMLGPU(wid
    mDrawDiagnostics(false),
    mUsingInvalidation(false),
    mCurrentFrame(nullptr)
 {
   if (!aWidget) {
     return;
   }
 
-  if (!mDevice) {
+#ifdef WIN32
+  mDevice = DeviceManagerDx::Get()->GetMLGDevice();
+#endif
+  if (!mDevice || !mDevice->IsValid()) {
     gfxWarning() << "Could not acquire an MLGDevice!";
     return;
   }
 
   mSwapChain = mDevice->CreateSwapChainForWidget(aWidget);
   if (!mSwapChain) {
     gfxWarning() << "Could not acquire an MLGSwapChain!";
     return;
--- a/gfx/layers/mlgpu/MLGDevice.h
+++ b/gfx/layers/mlgpu/MLGDevice.h
@@ -238,17 +238,16 @@ class MLGDevice
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MLGDevice)
 
   MLGDevice();
 
   virtual bool Initialize();
 
-  // If Initialize returns false, these may return more useful messages.
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() const = 0;
   virtual int32_t GetMaxTextureSize() const = 0;
   virtual LayersBackend GetLayersBackend() const = 0;
 
   virtual RefPtr<MLGSwapChain> CreateSwapChainForWidget(widget::CompositorWidget* aWidget) = 0;
 
   // Markers for when we start and finish issuing "normal" (i.e., non-
   // diagnostic) draw commands for the frame.
--- a/gfx/thebes/DeviceManagerDx.cpp
+++ b/gfx/thebes/DeviceManagerDx.cpp
@@ -7,33 +7,36 @@
 #include "D3D11Checks.h"
 #include "gfxConfig.h"
 #include "GfxDriverInfo.h"
 #include "gfxPrefs.h"
 #include "gfxWindowsPlatform.h"
 #include "mozilla/D3DMessageUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/WindowsVersion.h"
+#include "mozilla/gfx/GPUParent.h"
 #include "mozilla/gfx/GraphicsMessages.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
+#include "mozilla/layers/MLGDeviceD3D11.h"
 #include "nsIGfxInfo.h"
 #include <d3d11.h>
 #include <ddraw.h>
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #include "nsPrintfCString.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
 using namespace mozilla::widget;
+using namespace mozilla::layers;
 
 StaticAutoPtr<DeviceManagerDx> DeviceManagerDx::sInstance;
 
 // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
 // since it doesn't include d3d11.h, so we use a static here. It should only
 // be used within InitializeD3D11.
 decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
 
@@ -127,16 +130,24 @@ DeviceManagerDx::CreateCompositorDevices
     return false;
   }
 
   CreateCompositorDevice(d3d11);
 
   if (!d3d11.IsEnabled()) {
     MOZ_ASSERT(!mCompositorDevice);
     ReleaseD3D11();
+
+    // Sync Advanced-Layers with D3D11.
+    if (gfxConfig::IsEnabled(Feature::ADVANCED_LAYERS)) {
+      gfxConfig::SetFailed(Feature::ADVANCED_LAYERS,
+                           FeatureStatus::Unavailable,
+                           "Requires D3D11",
+                           NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_D3D11"));
+    }
     return false;
   }
 
   // We leak these everywhere and we need them our entire runtime anyway, let's
   // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
   // as well for D2D1 and device resets.
   mD3D11Module.disown();
 
@@ -602,23 +613,94 @@ DeviceManagerDx::CreateDecoderDevice()
     multi->SetMultithreadProtected(TRUE);
   }
   if (reuseDevice) {
     mDecoderDevice = device;
   }
   return device;
 }
 
+RefPtr<MLGDevice>
+DeviceManagerDx::GetMLGDevice()
+{
+  MutexAutoLock lock(mDeviceLock);
+  if (!mMLGDevice) {
+    MutexAutoUnlock unlock(mDeviceLock);
+    CreateMLGDevice();
+  }
+  return mMLGDevice;
+}
+
+static void
+DisableAdvancedLayers(FeatureStatus aStatus, const nsCString aMessage, const nsCString& aFailureId)
+{
+  if (!NS_IsMainThread()) {
+    NS_DispatchToMainThread(NS_NewRunnableFunction([aStatus, aMessage, aFailureId] () -> void {
+      DisableAdvancedLayers(aStatus, aMessage, aFailureId);
+    }));
+    return;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS);
+  if (!al.IsEnabled()) {
+    return;
+  }
+
+  al.SetFailed(aStatus, aMessage.get(), aFailureId);
+
+  FeatureFailure info(aStatus, aMessage, aFailureId);
+  if (GPUParent* gpu = GPUParent::GetSingleton()) {
+    gpu->SendUpdateFeature(Feature::ADVANCED_LAYERS, info);
+  }
+}
+
+void
+DeviceManagerDx::CreateMLGDevice()
+{
+  MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
+
+  RefPtr<ID3D11Device> d3d11Device = GetCompositorDevice();
+  if (!d3d11Device) {
+    DisableAdvancedLayers(FeatureStatus::Unavailable,
+                          NS_LITERAL_CSTRING("Advanced-layers requires a D3D11 device"),
+                          NS_LITERAL_CSTRING("FEATURE_FAILURE_NEED_D3D11_DEVICE"));
+    return;
+  }
+
+  RefPtr<MLGDeviceD3D11> device = new MLGDeviceD3D11(d3d11Device);
+  if (!device->Initialize()) {
+    DisableAdvancedLayers(FeatureStatus::Failed,
+                          device->GetFailureMessage(),
+                          device->GetFailureId());
+    return;
+  }
+
+  // While the lock was unheld, we should not have created an MLGDevice, since
+  // this should only be called on the compositor thread.
+  MutexAutoLock lock(mDeviceLock);
+  MOZ_ASSERT(!mMLGDevice);
+
+  // Only set the MLGDevice if the compositor device is still the same.
+  // Otherwise we could possibly have a bad MLGDevice if a device reset
+  // just occurred.
+  if (mCompositorDevice == d3d11Device) {
+    mMLGDevice = device;
+  }
+}
+
 void
 DeviceManagerDx::ResetDevices()
 {
   MutexAutoLock lock(mDeviceLock);
 
   mAdapter = nullptr;
   mCompositorAttachments = nullptr;
+  mMLGDevice = nullptr;
   mCompositorDevice = nullptr;
   mContentDevice = nullptr;
   mDeviceStatus = Nothing();
   mDeviceResetReason = Nothing();
   Factory::SetDirect3D11Device(nullptr);
 }
 
 bool
@@ -971,20 +1053,26 @@ DeviceManagerDx::GetCompositorDevices(Re
 /* static */ void
 DeviceManagerDx::PreloadAttachmentsOnCompositorThread()
 {
   MessageLoop* loop = layers::CompositorThreadHolder::Loop();
   if (!loop) {
     return;
   }
 
-  RefPtr<Runnable> task = NS_NewRunnableFunction([]() -> void {
+  bool enableAL = gfxConfig::IsEnabled(Feature::ADVANCED_LAYERS);
+
+  RefPtr<Runnable> task = NS_NewRunnableFunction([enableAL]() -> void {
     if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
-      RefPtr<ID3D11Device> device;
-      RefPtr<layers::DeviceAttachmentsD3D11> attachments;
-      dm->GetCompositorDevices(&device, &attachments);
+      if (enableAL) {
+        dm->GetMLGDevice();
+      } else {
+        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
@@ -32,16 +32,17 @@
 
 struct ID3D11Device;
 struct IDirectDraw7;
 
 namespace mozilla {
 class ScopedGfxFeatureReporter;
 namespace layers {
 class DeviceAttachmentsD3D11;
+class MLGDevice;
 } // namespace layers
 
 namespace gfx {
 class FeatureState;
 
 class DeviceManagerDx final
 {
 public:
@@ -52,16 +53,17 @@ public:
 
   static DeviceManagerDx* Get() {
     return sInstance;
   }
 
   RefPtr<ID3D11Device> GetCompositorDevice();
   RefPtr<ID3D11Device> GetContentDevice();
   RefPtr<ID3D11Device> CreateDecoderDevice();
+  RefPtr<layers::MLGDevice> GetMLGDevice();
   IDirectDraw7* GetDirectDraw();
 
   unsigned GetCompositorFeatureLevel() const;
   bool TextureSharingWorks();
   bool IsWARP();
 
   // Returns true if we can create a texture with
   // D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX and also
@@ -115,16 +117,17 @@ private:
   void CreateCompositorDevice(mozilla::gfx::FeatureState& d3d11);
   bool CreateCompositorDeviceHelper(
       mozilla::gfx::FeatureState& aD3d11,
       IDXGIAdapter1* aAdapter,
       bool aAttemptVideoSupport,
       RefPtr<ID3D11Device>& aOutDevice);
 
   void CreateWARPCompositorDevice();
+  void CreateMLGDevice();
 
   mozilla::gfx::FeatureStatus CreateContentDevice();
 
   bool CreateDevice(IDXGIAdapter* aAdapter,
                     D3D_DRIVER_TYPE aDriverType,
                     UINT aFlags,
                     HRESULT& aResOut,
                     RefPtr<ID3D11Device>& aOutDevice);
@@ -148,16 +151,17 @@ private:
 
   mozilla::Mutex mDeviceLock;
   nsTArray<D3D_FEATURE_LEVEL> mFeatureLevels;
   RefPtr<IDXGIAdapter1> mAdapter;
   RefPtr<ID3D11Device> mCompositorDevice;
   RefPtr<ID3D11Device> mContentDevice;
   RefPtr<ID3D11Device> mDecoderDevice;
   RefPtr<layers::DeviceAttachmentsD3D11> mCompositorAttachments;
+  RefPtr<layers::MLGDevice> mMLGDevice;
   bool mCompositorDeviceSupportsVideo;
 
   Maybe<D3D11DeviceStatus> mDeviceStatus;
 
   nsModuleHandle mDirectDrawDLL;
   RefPtr<IDirectDraw7> mDirectDraw;
 
   Maybe<DeviceResetReason> mDeviceResetReason;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2751,16 +2751,17 @@ gfxPlatform::BuildContentDeviceData(mozi
 }
 
 void
 gfxPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
 
   gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
+  gfxConfig::ImportChange(Feature::ADVANCED_LAYERS, aData.advancedLayers());
 }
 
 bool
 gfxPlatform::SupportsApzTouchInput() const
 {
   return dom::TouchEvent::PrefEnabled(nullptr);
 }
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -562,16 +562,17 @@ private:
   DECL_GFX_PREF(Live, "layers.max-active",                     MaxActiveLayers, int32_t, -1);
   DECL_GFX_PREF(Once, "layers.mlgpu.dev-enabled",              AdvancedLayersEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-buffer-cache",      AdvancedLayersEnableBufferCache, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-buffer-sharing",    AdvancedLayersEnableBufferSharing, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-clear-view",        AdvancedLayersEnableClearView, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-cpu-occlusion",     AdvancedLayersEnableCPUOcclusion, bool, true);
   DECL_GFX_PREF(Once, "layers.mlgpu.enable-depth-buffer",      AdvancedLayersEnableDepthBuffer, bool, false);
   DECL_GFX_PREF(Live, "layers.mlgpu.enable-invalidation",      AdvancedLayersUseInvalidation, bool, true);
+  DECL_GFX_PREF(Once, "layers.mlgpu.enable-on-windows7",       AdvancedLayersEnableOnWindows7, bool, false);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
   DECL_GFX_PREF(Live, "layers.orientation.sync.timeout",       OrientationSyncMillis, uint32_t, (uint32_t)0);
   DECL_GFX_PREF(Once, "layers.prefer-opengl",                  LayersPreferOpenGL, bool, false);
   DECL_GFX_PREF(Live, "layers.progressive-paint",              ProgressivePaint, bool, false);
   DECL_GFX_PREF(Live, "layers.shared-buffer-provider.enabled", PersistentBufferProviderSharedEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.single-tile.enabled",            LayersSingleTileEnabled, bool, true);
   DECL_GFX_PREF(Once, "layers.stereo-video.enabled",           StereoVideoEnabled, bool, false);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1380,16 +1380,38 @@ gfxWindowsPlatform::InitializeD3D11Confi
     d3d11.Disable(FeatureStatus::Blacklisted, message.get(), failureId);
   }
 
   // Check if the user really, really wants WARP.
   if (gfxPrefs::LayersD3D11ForceWARP()) {
     // Force D3D11 on even if we disabled it.
     d3d11.UserForceEnable("User force-enabled WARP");
   }
+
+  // Only enable Advanced Layers if D3D11 succeeded.
+  if (d3d11.IsEnabled()) {
+    FeatureState& al = gfxConfig::GetFeature(Feature::ADVANCED_LAYERS);
+
+    al.SetDefaultFromPref(
+      gfxPrefs::GetAdvancedLayersEnabledDoNotUseDirectlyPrefName(),
+      true /* aIsEnablePref */,
+      gfxPrefs::GetAdvancedLayersEnabledDoNotUseDirectlyPrefDefault());
+
+    // Windows 7 has an extra pref since it uses totally different buffer paths
+    // that haven't been performance tested yet.
+    if (al.IsEnabled() && !IsWin8OrLater()) {
+      if (gfxPrefs::AdvancedLayersEnableOnWindows7()) {
+        al.UserEnable("Enabled for Windows 7 via user-preference");
+      } else {
+        al.Disable(FeatureStatus::Disabled,
+                   "Advanced Layers is disabled on Windows 7 by default",
+                   NS_LITERAL_CSTRING("FEATURE_FAILURE_DISABLED_ON_WIN7"));
+      }
+    }
+  }
 }
 
 /* static */ void
 gfxWindowsPlatform::RecordContentDeviceFailure(TelemetryDeviceCode aDevice)
 {
   // If the parent process fails to acquire a device, we record this
   // normally as part of the environment. The exceptional case we're
   // looking for here is when the parent process successfully acquires
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -75,16 +75,17 @@
 #include "InputData.h"
 #include "FrameLayerBuilder.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 #include "gfxConfig.h"
 #include "mozilla/layers/CompositorSession.h"
 #include "VRManagerChild.h"
+#include "gfxConfig.h"
 
 #ifdef DEBUG
 #include "nsIObserver.h"
 
 static void debug_RegisterPrefCallbacks();
 
 #endif
 
@@ -1255,16 +1256,19 @@ void nsBaseWidget::CreateCompositor(int 
   }
 
   CreateCompositorVsyncDispatcher();
 
   bool enableWR = gfx::gfxVars::UseWebRender();
   bool enableAPZ = UseAPZ();
   CompositorOptions options(enableAPZ, enableWR);
 
+  bool enableAL = gfx::gfxConfig::IsEnabled(gfx::Feature::ADVANCED_LAYERS);
+  options.SetUseAdvancedLayers(enableAL);
+
   RefPtr<LayerManager> lm;
   if (options.UseWebRender()) {
     lm = new WebRenderLayerManager(this);
   } else {
     lm = new ClientLayerManager(this);
   }
 
   gfx::GPUProcessManager* gpu = gfx::GPUProcessManager::Get();