Add GPU draw time to the compositor diagnostic overlay. (bug 1352151 part 7, r=bas)
authorDavid Anderson <dvander@alliedmods.net>
Mon, 10 Apr 2017 19:44:46 -0700
changeset 560307 ee3f0299a518ff7158299b317648bf8d61fa35e3
parent 560306 2bfb1ea0619fb432c05ffb4b2a3a9304b9f866c7
child 560308 b72d2a630431dadf38e29095394d162991c84f7f
push id53365
push userjichen@mozilla.com
push dateTue, 11 Apr 2017 08:35:12 +0000
reviewersbas
bugs1352151
milestone55.0a1
Add GPU draw time to the compositor diagnostic overlay. (bug 1352151 part 7, r=bas)
gfx/layers/composite/Diagnostics.cpp
gfx/layers/composite/Diagnostics.h
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/d3d11/DiagnosticsD3D11.cpp
gfx/layers/d3d11/DiagnosticsD3D11.h
--- a/gfx/layers/composite/Diagnostics.cpp
+++ b/gfx/layers/composite/Diagnostics.cpp
@@ -56,28 +56,40 @@ Diagnostics::GetFrameOverlayString(const
 
   float pixelFillRatio = aStats.mInvalidPixels
                          ? float(aStats.mPixelsFilled) / float(aStats.mInvalidPixels)
                          : 0.0f;
   float screenFillRatio = aStats.mScreenPixels
                           ? float(aStats.mPixelsFilled) / float(aStats.mScreenPixels)
                           : 0.0f;
 
+  if (aStats.mDrawTime) {
+    mGPUDrawMs.Add(aStats.mDrawTime.value());
+  }
+
+  std::string gpuTimeString;
+  if (mGPUDrawMs.Empty()) {
+    gpuTimeString = "N/A";
+  } else {
+    gpuTimeString = nsPrintfCString("%0.1fms", mGPUDrawMs.Average()).get();
+  }
+
   // 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.1fms Exec: %0.1fms Fill Ratio: %0.1f/%0.1f",
+  nsPrintfCString line2("[CC] Build: %0.1fms Exec: %0.1fms GPU: %s Fill Ratio: %0.1f/%0.1f",
     mPrepareMs.Average(),
     mCompositeMs.Average(),
+    gpuTimeString.c_str(),
     pixelFillRatio,
     screenFillRatio);
   nsPrintfCString line3("[Content] DL: %0.1fms FLB: %0.1fms Raster: %0.1fms",
     mDlbMs.Average(),
     mFlbMs.Average(),
     mRasterMs.Average());
   nsPrintfCString line4("[IPDL] Build: %0.1fms Send: %0.1fms Update: %0.1fms",
     mSerializeMs.Average(),
--- a/gfx/layers/composite/Diagnostics.h
+++ b/gfx/layers/composite/Diagnostics.h
@@ -3,16 +3,17 @@
  * 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_composite_Diagnostics_h
 #define mozilla_gfx_layers_composite_Diagnostics_h
 
 #include "FPSCounter.h"
 #include "gfxPrefs.h"
+#include "mozilla/Maybe.h"
 #include "mozilla/TimeStamp.h"
 #include <deque>
 #include <string>
 #include <utility>
 
 namespace mozilla {
 namespace layers {
 
@@ -26,36 +27,42 @@ public:
   void Add(float aValue) {
     if (mHistory.size() > kMaxHistory) {
       mHistory.pop_front();
     }
     mHistory.push_back(Entry(aValue, TimeStamp::Now()));
   }
 
   float Average() const;
+  bool Empty() const {
+    return mHistory.empty();
+  }
 
 private:
   static const size_t kMaxHistory = 60;
 
   std::deque<Entry> mHistory;
 };
 
+// These statistics are collected by layers backends, preferably by the GPU
 struct GPUStats
 {
   GPUStats()
    : mInvalidPixels(0),
      mScreenPixels(0),
      mPixelsFilled(0)
   {}
 
   uint32_t mInvalidPixels;
   uint32_t mScreenPixels;
   uint32_t mPixelsFilled;
+  Maybe<float> mDrawTime;
 };
 
+// Collects various diagnostics about layers performance.
 class Diagnostics
 {
 public:
   Diagnostics();
 
   void RecordPaintTimes(const PaintTiming& aPaintTimes);
   void RecordUpdateTime(float aValue) {
     mUpdateMs.Add(aValue);
@@ -96,14 +103,15 @@ private:
   TimedMetric mDlbMs;
   TimedMetric mFlbMs;
   TimedMetric mRasterMs;
   TimedMetric mSerializeMs;
   TimedMetric mSendMs;
   TimedMetric mUpdateMs;
   TimedMetric mPrepareMs;
   TimedMetric mCompositeMs;
+  TimedMetric mGPUDrawMs;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_gfx_layers_composite_Diagnostics_h
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -548,17 +548,17 @@ LayerManagerComposite::RootLayer() const
 void
 LayerManagerComposite::InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const IntRect& aBounds)
 {
   bool drawFps = gfxPrefs::LayersDrawFPS();
   bool drawFrameCounter = gfxPrefs::DrawFrameCounter();
   bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
 
   if (drawFps || drawFrameCounter) {
-    aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 600, 400));
+    aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 650, 400));
   }
   if (drawFrameColorBars) {
     aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 10, aBounds.height));
   }
 
 #ifdef USE_SKIA
   bool drawPaintTimes = gfxPrefs::AlwaysPaint();
   if (drawPaintTimes) {
@@ -634,17 +634,17 @@ LayerManagerComposite::RenderDebugOverla
 
     std::string text = mDiagnostics->GetFrameOverlayString(stats);
     mTextRenderer->RenderText(
       mCompositor,
       text,
       IntPoint(2, 5),
       Matrix4x4(),
       30,
-      600);
+      650);
 
     if (mUnusedApzTransformWarning) {
       // If we have an unused APZ transform on this composite, draw a 20x20 red box
       // in the top-right corner
       EffectChain effects;
       effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(1, 0, 0, 1));
       mCompositor->DrawQuad(gfx::Rect(aBounds.width - 20, 0, 20, 20),
                             aBounds, effects, alpha, gfx::Matrix4x4());
--- a/gfx/layers/d3d11/DiagnosticsD3D11.cpp
+++ b/gfx/layers/d3d11/DiagnosticsD3D11.cpp
@@ -23,24 +23,46 @@ DiagnosticsD3D11::Start(uint32_t aPixels
   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;
+
+  desc = CD3D11_QUERY_DESC(D3D11_QUERY_TIMESTAMP_DISJOINT);
+  mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.timing));
+  if (mCurrentFrame.timing) {
+    mContext->Begin(mCurrentFrame.timing);
+  }
+
+  desc = CD3D11_QUERY_DESC(D3D11_QUERY_TIMESTAMP);
+  mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.frameBegin));
+  if (mCurrentFrame.frameBegin) {
+    mContext->End(mCurrentFrame.frameBegin);
+  }
 }
 
 void
 DiagnosticsD3D11::End()
 {
   if (mCurrentFrame.stats) {
     mContext->End(mCurrentFrame.stats);
   }
+  if (mCurrentFrame.frameBegin) {
+    CD3D11_QUERY_DESC desc(D3D11_QUERY_TIMESTAMP);
+    mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.frameEnd));
+    if (mCurrentFrame.frameEnd) {
+      mContext->End(mCurrentFrame.frameEnd);
+    }
+  }
+  if (mCurrentFrame.timing) {
+    mContext->End(mCurrentFrame.timing);
+  }
 }
 
 void
 DiagnosticsD3D11::Cancel()
 {
   mCurrentFrame = FrameQueries();
 }
 
@@ -50,13 +72,25 @@ 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);
     }
   }
+  if (mPrevFrame.timing) {
+    UINT64 begin, end;
+    D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timing;
+    if (WaitForGPUQuery(mDevice, mContext, mPrevFrame.timing, &timing) &&
+        !timing.Disjoint &&
+        WaitForGPUQuery(mDevice, mContext, mPrevFrame.frameBegin, &begin) &&
+        WaitForGPUQuery(mDevice, mContext, mPrevFrame.frameEnd, &end))
+    {
+      float timeMs = float(end - begin) / float(timing.Frequency) * 1000.0f;
+      aStats->mDrawTime = Some(timeMs);
+    }
+  }
 }
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/d3d11/DiagnosticsD3D11.h
+++ b/gfx/layers/d3d11/DiagnosticsD3D11.h
@@ -32,16 +32,19 @@ private:
 
   // When using the diagnostic overlay, we double-buffer some queries for
   // frame statistics.
   struct FrameQueries {
     FrameQueries() : pixelsPerFrame(0)
     {}
 
     RefPtr<ID3D11Query> stats;
+    RefPtr<ID3D11Query> timing;
+    RefPtr<ID3D11Query> frameBegin;
+    RefPtr<ID3D11Query> frameEnd;
     uint32_t pixelsPerFrame;
   };
   FrameQueries mPrevFrame;
   FrameQueries mCurrentFrame;
 };
 
 } // namespace layers
 } // namespace mozilla