Improve pixel fill statistics in the D3D11 compositor overlay. (bug 1352151 part 6, r=bas)
authorDavid Anderson <dvander@alliedmods.net>
Mon, 10 Apr 2017 19:44:46 -0700
changeset 560306 2bfb1ea0619fb432c05ffb4b2a3a9304b9f866c7
parent 560305 df901e207ad2a25a7f6ca31f8e9ce74a95e1d4e5
child 560307 ee3f0299a518ff7158299b317648bf8d61fa35e3
push id53365
push userjichen@mozilla.com
push dateTue, 11 Apr 2017 08:35:12 +0000
reviewersbas
bugs1352151
milestone55.0a1
Improve pixel fill statistics in the D3D11 compositor overlay. (bug 1352151 part 6, r=bas) This introduces two new statistics to the overlay. The first is the ratio of pixel shader invocations (as determined by the GPU) to the number of pixels we determined need to be redrawn. The ideal ratio is 1.0, indicating that we filled every pixel exactly once. Anything over 1.0 indicates overdraw. We also add the ratio of shaded pixels to window size. This indicates how well we computed the invalid region, and whether or not we overfilled that region. Note that the OpenGL and Basic compositors do not yet query the GPU for this statistic, so they will estimate shader invocations by the area of DrawQuad calls. Finally, we remove the feature where layout can request the most recent overdraw statistic. It was not implemented on all compositors, and the only test that used it was disabled.
gfx/layers/Compositor.cpp
gfx/layers/Compositor.h
gfx/layers/composite/Diagnostics.cpp
gfx/layers/composite/Diagnostics.h
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/d3d11/CompositorD3D11.cpp
gfx/layers/d3d11/CompositorD3D11.h
gfx/layers/d3d11/DiagnosticsD3D11.cpp
gfx/layers/d3d11/DiagnosticsD3D11.h
gfx/layers/d3d11/HelpersD3D11.h
gfx/layers/ipc/LayerTransactionParent.cpp
gfx/layers/moz.build
gfx/layers/wr/WebRenderCanvasLayer.cpp
gfx/layers/wr/WebRenderCanvasLayer.h
gfx/tests/mochitest/mochitest.ini
gfx/tests/mochitest/test_overdraw.html
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "mozilla/layers/Compositor.h"
 #include "base/message_loop.h"          // for MessageLoop
 #include "mozilla/layers/CompositorBridgeParent.h"  // for CompositorBridgeParent
+#include "mozilla/layers/Diagnostics.h"
 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "gfx2DGlue.h"
 #include "nsAppRunner.h"
 
@@ -634,10 +635,17 @@ bool
 Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
 {
   if (IsDestroyed() || AsBasicCompositor()) {
     return false;
   }
   return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
 }
 
+void
+Compositor::GetFrameStats(GPUStats* aStats)
+{
+  aStats->mInvalidPixels = mPixelsPerFrame;
+  aStats->mPixelsFilled = mPixelsFilled;
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -129,16 +129,17 @@ class TextureSource;
 class DataTextureSource;
 class CompositingRenderTarget;
 class CompositorBridgeParent;
 class LayerManagerComposite;
 class CompositorOGL;
 class CompositorD3D11;
 class BasicCompositor;
 class TextureReadLock;
+struct GPUStats;
 
 enum SurfaceInitMode
 {
   INIT_MODE_NONE,
   INIT_MODE_CLEAR
 };
 
 /**
@@ -400,16 +401,22 @@ public:
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::IntRect* aClipRectIn,
                           const gfx::IntRect& aRenderBounds,
                           const nsIntRegion& aOpaqueRegion,
                           gfx::IntRect* aClipRectOut = nullptr,
                           gfx::IntRect* aRenderBoundsOut = nullptr) = 0;
 
   /**
+   * Notification that we've finished issuing draw commands for normal
+   * layers (as opposed to the diagnostic overlay which comes after).
+   */
+  virtual void NormalDrawingDone() {}
+
+  /**
    * Flush the current frame to the screen and tidy up.
    *
    * Derived class overriding this should call Compositor::EndFrame.
    */
   virtual void EndFrame();
 
   virtual void CancelFrame() { ReadUnlockTextures(); }
 
@@ -507,26 +514,18 @@ public:
   widget::CompositorWidget* GetWidget() const { return mWidget; }
 
   /**
    * Debug-build assertion that can be called to ensure code is running on the
    * compositor thread.
    */
   static void AssertOnCompositorThread();
 
-  size_t GetFillRatio() {
-    float fillRatio = 0;
-    if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
-      fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
-      if (fillRatio > 999.0f) {
-        fillRatio = 999.0f;
-      }
-    }
-    return fillRatio;
-  }
+  // Return statistics for the most recent frame we computed statistics for.
+  virtual void GetFrameStats(GPUStats* aStats);
 
   ScreenRotation GetScreenRotation() const {
     return mScreenRotation;
   }
   void SetScreenRotation(ScreenRotation aRotation) {
     mScreenRotation = aRotation;
   }
 
--- a/gfx/layers/composite/Diagnostics.cpp
+++ b/gfx/layers/composite/Diagnostics.cpp
@@ -43,39 +43,52 @@ Diagnostics::RecordPaintTimes(const Pain
   mDlbMs.Add(aPaintTimes.dlMs());
   mFlbMs.Add(aPaintTimes.flbMs());
   mRasterMs.Add(aPaintTimes.rasterMs());
   mSerializeMs.Add(aPaintTimes.serializeMs());
   mSendMs.Add(aPaintTimes.sendMs());
 }
 
 std::string
-Diagnostics::GetFrameOverlayString()
+Diagnostics::GetFrameOverlayString(const GPUStats& aStats)
 {
   TimeStamp now = TimeStamp::Now();
   unsigned fps = unsigned(mCompositeFps.AddFrameAndGetFps(now));
   unsigned txnFps = unsigned(mTransactionFps.GetFPS(now));
 
+  float pixelFillRatio = aStats.mInvalidPixels
+                         ? float(aStats.mPixelsFilled) / float(aStats.mInvalidPixels)
+                         : 0.0f;
+  float screenFillRatio = aStats.mScreenPixels
+                          ? float(aStats.mPixelsFilled) / float(aStats.mScreenPixels)
+                          : 0.0f;
+
   // DL  = nsDisplayListBuilder
   // FLB = FrameLayerBuilder
   // R   = ClientLayerManager::EndTransaction
   // CP  = ShadowLayerForwarder::EndTransaction (txn build)
   // TX  = LayerTransactionChild::SendUpdate (IPDL serialize+send)
   // UP  = LayerTransactionParent::RecvUpdate (IPDL deserialize, update, APZ update)
   // CC_BUILD = Container prepare/composite frame building
   // CC_EXEC  = Container render/composite drawing
   nsPrintfCString line1("FPS: %d (TXN: %d)", fps, txnFps);
-  nsPrintfCString line2("CC_BUILD: %0.1f CC_EXEC: %0.1f",
+  nsPrintfCString line2("[CC] Build: %0.1fms Exec: %0.1fms Fill Ratio: %0.1f/%0.1f",
     mPrepareMs.Average(),
-    mCompositeMs.Average());
-  nsPrintfCString line3("DL: %0.1f FLB: %0.1f R: %0.1f CP: %0.1f TX: %0.1f UP: %0.1f",
+    mCompositeMs.Average(),
+    pixelFillRatio,
+    screenFillRatio);
+  nsPrintfCString line3("[Content] DL: %0.1fms FLB: %0.1fms Raster: %0.1fms",
     mDlbMs.Average(),
     mFlbMs.Average(),
-    mRasterMs.Average(),
+    mRasterMs.Average());
+  nsPrintfCString line4("[IPDL] Build: %0.1fms Send: %0.1fms Update: %0.1fms",
     mSerializeMs.Average(),
     mSendMs.Average(),
     mUpdateMs.Average());
 
-  return std::string(line1.get()) + ", " + std::string(line2.get()) + "\n" + std::string(line3.get());
+  return std::string(line1.get()) + "\n" +
+         std::string(line2.get()) + "\n" +
+         std::string(line3.get()) + "\n" +
+         std::string(line4.get());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/Diagnostics.h
+++ b/gfx/layers/composite/Diagnostics.h
@@ -33,16 +33,29 @@ public:
   float Average() const;
 
 private:
   static const size_t kMaxHistory = 60;
 
   std::deque<Entry> mHistory;
 };
 
+struct GPUStats
+{
+  GPUStats()
+   : mInvalidPixels(0),
+     mScreenPixels(0),
+     mPixelsFilled(0)
+  {}
+
+  uint32_t mInvalidPixels;
+  uint32_t mScreenPixels;
+  uint32_t mPixelsFilled;
+};
+
 class Diagnostics
 {
 public:
   Diagnostics();
 
   void RecordPaintTimes(const PaintTiming& aPaintTimes);
   void RecordUpdateTime(float aValue) {
     mUpdateMs.Add(aValue);
@@ -52,17 +65,17 @@ public:
   }
   void RecordCompositeTime(float aValue) {
     mCompositeMs.Add(aValue);
   }
   void AddTxnFrame() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
 
-  std::string GetFrameOverlayString();
+  std::string GetFrameOverlayString(const GPUStats& aStats);
 
   class Record {
   public:
     Record() {
       if (gfxPrefs::LayersDrawFPS()) {
         mStart = TimeStamp::Now();
       }
     }
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -623,17 +623,21 @@ LayerManagerComposite::RenderDebugOverla
       mCompositor->DrawQuad(gfx::Rect(border, border + width, width, aBounds.height - 2 * border - width * 2),
                             aBounds, effects, alpha, gfx::Matrix4x4());
       mCompositor->DrawQuad(gfx::Rect(aBounds.width - border - width, border + width, width, aBounds.height - 2 * border - 2 * width),
                             aBounds, effects, alpha, gfx::Matrix4x4());
       SetDebugOverlayWantsNextFrame(true);
     }
 #endif
 
-    std::string text = mDiagnostics->GetFrameOverlayString();
+    GPUStats stats;
+    stats.mScreenPixels = mRenderBounds.width * mRenderBounds.height;
+    mCompositor->GetFrameStats(&stats);
+
+    std::string text = mDiagnostics->GetFrameOverlayString(stats);
     mTextRenderer->RenderText(
       mCompositor,
       text,
       IntPoint(2, 5),
       Matrix4x4(),
       30,
       600);
 
@@ -965,16 +969,18 @@ LayerManagerComposite::Render(const nsIn
     PopGroupForLayerEffects(previousTarget, clipRect.ToUnknownRect(),
                             grayscaleVal, invertVal, contrastVal);
   }
 
   // Allow widget to render a custom foreground.
   mCompositor->GetWidget()->DrawWindowOverlay(
     &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
 
+  mCompositor->NormalDrawingDone();
+
   // Debugging
   RenderDebugOverlay(actualBounds);
 
   {
     PROFILER_LABEL("LayerManagerComposite", "EndFrame",
       js::ProfileEntry::Category::GRAPHICS);
 
     mCompositor->EndFrame();
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -10,17 +10,20 @@
 
 #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"
+#include "mozilla/layers/Diagnostics.h"
+#include "mozilla/layers/DiagnosticsD3D11.h"
 #include "mozilla/layers/Effects.h"
+#include "mozilla/layers/HelpersD3D11.h"
 #include "nsWindowsHelpers.h"
 #include "gfxPrefs.h"
 #include "gfxConfig.h"
 #include "gfxCrashReporterUtils.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/StackArray.h"
 #include "mozilla/Services.h"
 #include "mozilla/widget/WinCompositorWidget.h"
@@ -281,16 +284,17 @@ CompositorD3D11::Initialize(nsCString* c
 
   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);
@@ -1393,32 +1397,31 @@ CompositorD3D11::BeginFrame(const nsIntR
         gfxCriticalNote << "GFX: D3D11 timeout with device-removed:" << gfx::hexa(hr);
         *aRenderBoundsOut = IntRect();
         return;
       } else if (hr == WAIT_ABANDONED) {
         gfxCriticalNote << "GFX: D3D11 abandoned sync";
       }
     }
   }
+
+  if (gfxPrefs::LayersDrawFPS()) {
+    uint32_t pixelsPerFrame = 0;
+    for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
+      pixelsPerFrame += iter.Get().width * iter.Get().height;
+    }
+
+    mDiagnostics->Start(pixelsPerFrame);
+  }
 }
 
-template <typename T> static inline bool
-WaitForGPUQuery(ID3D11Device* aDevice, ID3D11DeviceContext* aContext, ID3D11Query* aQuery, T* aOut)
+void
+CompositorD3D11::NormalDrawingDone()
 {
-  TimeStamp start = TimeStamp::Now();
-  while (aContext->GetData(aQuery, aOut, sizeof(*aOut), 0) != S_OK) {
-    if (aDevice->GetDeviceRemovedReason() != S_OK) {
-      return false;
-    }
-    if (TimeStamp::Now() - start > TimeDuration::FromSeconds(2)) {
-      return false;
-    }
-    Sleep(0);
-  }
-  return true;
+  mDiagnostics->End();
 }
 
 void
 CompositorD3D11::EndFrame()
 {
   if (!mDefaultRT) {
     Compositor::EndFrame();
     return;
@@ -1442,32 +1445,40 @@ CompositorD3D11::EndFrame()
   CD3D11_QUERY_DESC  desc(D3D11_QUERY_EVENT);
   mDevice->CreateQuery(&desc, getter_AddRefs(query));
   if (query) {
     mContext->End(query);
   }
 
   if (oldSize == mSize) {
     Present();
+  } else {
+    mDiagnostics->Cancel();
   }
 
   // Block until the previous frame's work has been completed.
   if (mQuery) {
     BOOL result;
     WaitForGPUQuery(mDevice, mContext, mQuery, &result);
   }
   // Store the query for this frame so we can flush it next time.
   mQuery = query;
 
   Compositor::EndFrame();
 
   mCurrentRT = nullptr;
 }
 
 void
+CompositorD3D11::GetFrameStats(GPUStats* aStats)
+{
+  mDiagnostics->Query(aStats);
+}
+
+void
 CompositorD3D11::Present()
 {
   UINT presentInterval = 0;
 
   bool isWARP = DeviceManagerDx::Get()->IsWARP();
   if (isWARP) {
     // When we're using WARP we cannot present immediately as it causes us
     // to tear when rendering. When not using WARP it appears the DWM takes
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -35,16 +35,17 @@ struct PixelShaderConstants
 {
   float layerColor[4];
   float layerOpacity[4];
   int blendConfig[4];
   float yuvColorMatrix[3][4];
 };
 
 struct DeviceAttachmentsD3D11;
+class DiagnosticsD3D11;
 
 class CompositorD3D11 : public Compositor
 {
 public:
   CompositorD3D11(CompositorBridgeParent* aParent, widget::CompositorWidget* aWidget);
   ~CompositorD3D11();
 
   virtual CompositorD3D11* AsCompositorD3D11() override { return this; }
@@ -106,16 +107,18 @@ public:
    */
   virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
                           const gfx::IntRect *aClipRectIn,
                           const gfx::IntRect& aRenderBounds,
                           const nsIntRegion& aOpaqueRegion,
                           gfx::IntRect *aClipRectOut = nullptr,
                           gfx::IntRect *aRenderBoundsOut = nullptr) override;
 
+  void NormalDrawingDone() override;
+
   /**
    * Flush the current frame to the screen.
    */
   virtual void EndFrame() override;
 
   virtual void CancelFrame() override;
 
   /**
@@ -202,16 +205,18 @@ private:
 
   // Overloads for rendering both rects and triangles with same rendering path
   void Draw(const nsTArray<gfx::TexturedTriangle>& aGeometry,
             const gfx::Rect* aTexCoords);
 
   void Draw(const gfx::Rect& aGeometry,
             const gfx::Rect* aTexCoords);
 
+  void GetFrameStats(GPUStats* aStats) override;
+
   void Present();
 
   ID3D11VertexShader* GetVSForGeometry(const nsTArray<gfx::TexturedTriangle>& aTriangles,
                                        const bool aUseBlendShader,
                                        const MaskType aMaskType);
 
   ID3D11VertexShader* GetVSForGeometry(const gfx::Rect& aRect,
                                        const bool aUseBlendShader,
@@ -224,16 +229,17 @@ private:
   RefPtr<ID3D11Device> mDevice;
   RefPtr<IDXGISwapChain> mSwapChain;
   RefPtr<CompositingRenderTargetD3D11> mDefaultRT;
   RefPtr<CompositingRenderTargetD3D11> mCurrentRT;
 
   RefPtr<ID3D11Query> mQuery;
 
   DeviceAttachmentsD3D11* mAttachments;
+  UniquePtr<DiagnosticsD3D11> mDiagnostics;
 
   LayoutDeviceIntSize mSize;
 
   HWND mHwnd;
 
   D3D_FEATURE_LEVEL mFeatureLevel;
 
   VertexShaderConstants mVSConstants;
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d11/DiagnosticsD3D11.cpp
@@ -0,0 +1,62 @@
+/* -*- 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 "DiagnosticsD3D11.h"
+#include "mozilla/layers/Diagnostics.h"
+#include "mozilla/layers/HelpersD3D11.h"
+
+namespace mozilla {
+namespace layers {
+
+DiagnosticsD3D11::DiagnosticsD3D11(ID3D11Device* aDevice, ID3D11DeviceContext* aContext)
+ : mDevice(aDevice),
+   mContext(aContext)
+{
+}
+
+void
+DiagnosticsD3D11::Start(uint32_t aPixelsPerFrame)
+{
+  mPrevFrame = mCurrentFrame;
+  mCurrentFrame = FrameQueries();
+
+  CD3D11_QUERY_DESC desc(D3D11_QUERY_PIPELINE_STATISTICS);
+  mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.stats));
+  if (mCurrentFrame.stats) {
+    mContext->Begin(mCurrentFrame.stats);
+  }
+  mCurrentFrame.pixelsPerFrame = aPixelsPerFrame;
+}
+
+void
+DiagnosticsD3D11::End()
+{
+  if (mCurrentFrame.stats) {
+    mContext->End(mCurrentFrame.stats);
+  }
+}
+
+void
+DiagnosticsD3D11::Cancel()
+{
+  mCurrentFrame = FrameQueries();
+}
+
+void
+DiagnosticsD3D11::Query(GPUStats* aStats)
+{
+  // Collect pixel shader stats.
+  if (mPrevFrame.stats) {
+    D3D11_QUERY_DATA_PIPELINE_STATISTICS stats;
+    if (WaitForGPUQuery(mDevice, mContext, mPrevFrame.stats, &stats)) {
+      aStats->mInvalidPixels = mPrevFrame.pixelsPerFrame;
+      aStats->mPixelsFilled = uint32_t(stats.PSInvocations);
+    }
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d11/DiagnosticsD3D11.h
@@ -0,0 +1,49 @@
+/* -*- 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_DiagnosticsD3D11_h
+#define mozilla_gfx_layers_d3d11_DiagnosticsD3D11_h
+
+#include <stdint.h>
+#include "mozilla/RefPtr.h"
+#include <d3d11.h>
+
+namespace mozilla {
+namespace layers {
+
+struct GPUStats;
+
+class DiagnosticsD3D11
+{
+public:
+  DiagnosticsD3D11(ID3D11Device* aDevice, ID3D11DeviceContext* aContext);
+
+  void Start(uint32_t aPixelsPerFrame);
+  void End();
+  void Cancel();
+
+  void Query(GPUStats* aStats);
+
+private:
+  RefPtr<ID3D11Device> mDevice;
+  RefPtr<ID3D11DeviceContext> mContext;
+
+  // When using the diagnostic overlay, we double-buffer some queries for
+  // frame statistics.
+  struct FrameQueries {
+    FrameQueries() : pixelsPerFrame(0)
+    {}
+
+    RefPtr<ID3D11Query> stats;
+    uint32_t pixelsPerFrame;
+  };
+  FrameQueries mPrevFrame;
+  FrameQueries mCurrentFrame;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_d3d11_DiagnosticsD3D11_h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/d3d11/HelpersD3D11.h
@@ -0,0 +1,34 @@
+/* -*- 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_HelpersD3D11_h
+#define mozilla_gfx_layers_d3d11_HelpersD3D11_h
+
+#include <d3d11.h>
+#include "mozilla/TimeStamp.h"
+
+namespace mozilla {
+namespace layers {
+
+template <typename T> static inline bool
+WaitForGPUQuery(ID3D11Device* aDevice, ID3D11DeviceContext* aContext, ID3D11Query* aQuery, T* aOut)
+{
+  TimeStamp start = TimeStamp::Now();
+  while (aContext->GetData(aQuery, aOut, sizeof(*aOut), 0) != S_OK) {
+    if (aDevice->GetDeviceRemovedReason() != S_OK) {
+      return false;
+    }
+    if (TimeStamp::Now() - start > TimeDuration::FromSeconds(2)) {
+      return false;
+    }
+    Sleep(0);
+  }
+  return true;
+}
+
+} // namespace layers
+} // namespace gfx
+
+#endif // mozilla_gfx_layers_d3d11_HelpersD3D11_h
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -838,21 +838,17 @@ LayerTransactionParent::RecvGetAPZTestDa
 {
   mCompositorBridge->GetAPZTestData(this, aOutData);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aValue)
 {
-  if (aProperty.Equals(NS_LITERAL_STRING("overdraw"))) {
-    *aValue = layer_manager()->GetCompositor()->GetFillRatio();
-  } else {
-    *aValue = -1;
-  }
+  *aValue = -1;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 LayerTransactionParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
                                                    nsTArray<ScrollableLayerGuid>&& aTargets)
 {
   mCompositorBridge->SetConfirmedTargetAPZC(this, aBlockId, aTargets);
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -57,20 +57,23 @@ 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/DiagnosticsD3D11.h',
+            'd3d11/HelpersD3D11.h',
             'd3d11/ReadbackManagerD3D11.h',
             'd3d11/TextureD3D11.h',
         ]
         UNIFIED_SOURCES += [
+            'd3d11/DiagnosticsD3D11.cpp',
             'd3d11/TextureD3D11.cpp',
         ]
         SOURCES += [
             'd3d11/CompositorD3D11.cpp',
             'd3d11/ReadbackManagerD3D11.cpp',
         ]
 
 EXPORTS.gfxipc += [
@@ -127,16 +130,18 @@ EXPORTS.mozilla.layers += [
     'client/TextureClientSharedSurface.h',
     'client/TiledContentClient.h',
     'composite/AnimationMetricsTracker.h',
     'composite/AsyncCompositionManager.h',
     'composite/CanvasLayerComposite.h',
     'composite/ColorLayerComposite.h',
     'composite/ContainerLayerComposite.h',
     'composite/ContentHost.h',
+    'composite/Diagnostics.h',
+    'composite/FPSCounter.h',
     'composite/FrameUniformityData.h',
     'composite/GPUVideoTextureHost.h',
     'composite/ImageComposite.h',
     'composite/ImageHost.h',
     'composite/ImageLayerComposite.h',
     'composite/LayerManagerComposite.h',
     'composite/PaintedLayerComposite.h',
     'composite/TextureHost.h',
--- a/gfx/layers/wr/WebRenderCanvasLayer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasLayer.cpp
@@ -98,10 +98,16 @@ WebRenderCanvasLayer::RenderLayer(wr::Di
 }
 
 void
 WebRenderCanvasLayer::AttachCompositable()
 {
   mCanvasClient->Connect();
 }
 
+CompositableForwarder*
+WebRenderCanvasLayer::GetForwarder()
+{
+  return Manager()->WrBridge();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderCanvasLayer.h
+++ b/gfx/layers/wr/WebRenderCanvasLayer.h
@@ -24,20 +24,17 @@ public:
     : ShareableCanvasLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
     , mExternalImageId(0)
   {
     MOZ_COUNT_CTOR(WebRenderCanvasLayer);
   }
 
   virtual void Initialize(const Data& aData) override;
 
-  virtual CompositableForwarder* GetForwarder() override
-  {
-    return Manager()->WrBridge();
-  }
+  virtual CompositableForwarder* GetForwarder() override;
 
   virtual void AttachCompositable() override;
 
 protected:
   virtual ~WebRenderCanvasLayer();
   WebRenderLayerManager* Manager()
   {
     return static_cast<WebRenderLayerManager*>(mManager);
--- a/gfx/tests/mochitest/mochitest.ini
+++ b/gfx/tests/mochitest/mochitest.ini
@@ -1,11 +1,8 @@
 [DEFAULT]
 
 [test_acceleration.html]
 subsuite = gpu
 fail-if = (os == "win" && os_version == "5.1" && e10s) # Bug 1253862
 [test_bug509244.html]
 [test_bug513439.html]
 [test_font_whitelist.html]
-[test_overdraw.html]
-# Disable test until bug 1064136 is fixed
-skip-if = true
deleted file mode 100644
--- a/gfx/tests/mochitest/test_overdraw.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test overdraw</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<script type="application/javascript">
-var domWindowUtils = SpecialPowers.getDOMWindowUtils(window);
-
-var overdraw = domWindowUtils.requestCompositorProperty("overdraw");
-
-if (overdraw == -1) {
-  // Overdraw queries are not supported on non OMTC builds.
-  ok(overdraw == -1, "Platform doesn't use a compositor.");
-} else {
-  // Overdraw may be lower than 100% like on OS X where we don't
-  // composite the window corners.
-  ok(overdraw > 0.95 && overdraw < 200, "Overdraw: " + overdraw);
-}
-</script>
-</body>