Bug 1392476 - Add dropframe telemetry for WebVR; r?kip, francois draft
authorDaosheng Mu <daoshengmu@gmail.com>
Mon, 28 Aug 2017 18:43:25 +0800
changeset 660447 264db9fb0dbc2d37c5c1de8d413e3fc38123c3d8
parent 657025 14eea6bedcf3e2f46ea7c908e1ac9b7d256a42f0
child 730246 76c6ed6dcda364f05bfda9255edf0676919cb0de
push id78413
push userbmo:dmu@mozilla.com
push dateThu, 07 Sep 2017 02:08:33 +0000
reviewerskip, francois
bugs1392476
milestone57.0a1
Bug 1392476 - Add dropframe telemetry for WebVR; r?kip, francois MozReview-Commit-ID: IPVnPBkY8CN
gfx/vr/gfxVR.h
gfx/vr/gfxVROculus.cpp
gfx/vr/gfxVROculus.h
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVROpenVR.h
toolkit/components/telemetry/Histograms.json
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -306,16 +306,35 @@ struct VRControllerInfo
            mNumHaptics == other.mNumHaptics;
   }
 
   bool operator!=(const VRControllerInfo& other) const {
     return !(*this == other);
   }
 };
 
+struct VRTelemetry
+{
+  VRTelemetry()
+   : mLastDroppedFrameCount(-1)
+  {}
+
+  void Clear() {
+    mPresentationStart = TimeStamp();
+    mLastDroppedFrameCount = -1;
+  }
+
+  bool IsLastDroppedFrameValid() {
+    return (mLastDroppedFrameCount != -1);
+  }
+
+  TimeStamp mPresentationStart;
+  int32_t mLastDroppedFrameCount;
+};
+
 class VRSystemManager {
 public:
   static uint32_t AllocateDisplayID();
   static uint32_t AllocateControllerID();
 
 protected:
   static Atomic<uint32_t> sDisplayBase;
   static Atomic<uint32_t> sControllerBase;
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -228,29 +228,50 @@ VROculusSession::StopTracking()
 
 void
 VROculusSession::StartPresentation(const IntSize& aSize)
 {
   if (!mPresenting) {
     mPresenting = true;
     mPresentationSize = aSize;
     Refresh();
-    mPresentationStart = TimeStamp::Now();
+    mTelemetry.Clear();
+    mTelemetry.mPresentationStart = TimeStamp::Now();
+
+    ovrPerfStats perfStats;
+    if (ovr_GetPerfStats(mSession, &perfStats) == ovrSuccess) {
+      if (perfStats.FrameStatsCount) {
+        mTelemetry.mLastDroppedFrameCount = perfStats.FrameStats[0].AppDroppedFrameCount;
+      }
+    }
   }
 }
 
 void
 VROculusSession::StopPresentation()
 {
   if (mPresenting) {
     mLastPresentationEnd = TimeStamp::Now();
     mPresenting = false;
+
+    const TimeDuration duration = mLastPresentationEnd - mTelemetry.mPresentationStart;
     Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 1);
-    Telemetry::AccumulateTimeDelta(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OCULUS,
-                                   mPresentationStart);
+    Telemetry::Accumulate(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OCULUS,
+                          duration.ToMilliseconds());
+
+    if (mTelemetry.IsLastDroppedFrameValid() && duration.ToSeconds()) {
+      ovrPerfStats perfStats;
+      if (ovr_GetPerfStats(mSession, &perfStats) == ovrSuccess) {
+        if (perfStats.FrameStatsCount) {
+          const uint32_t droppedFramesPerSec = (perfStats.FrameStats[0].AppDroppedFrameCount -
+                                                mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds();
+          Telemetry::Accumulate(Telemetry::WEBVR_DROPPED_FRAMES_IN_OCULUS, droppedFramesPerSec);
+        }
+      }
+    }
     Refresh();
   }
 }
 
 VROculusSession::~VROculusSession()
 {
   Uninitialize(true);
 }
--- a/gfx/vr/gfxVROculus.h
+++ b/gfx/vr/gfxVROculus.h
@@ -32,16 +32,17 @@ enum class OculusControllerAxisType : ui
   ThumbstickXAxis,
   ThumbstickYAxis,
   NumVRControllerAxisType
 };
 
 class VROculusSession
 {
   NS_INLINE_DECL_REFCOUNTING(VROculusSession);
+  friend class VRDisplayOculus;
 public:
   VROculusSession();
   void Refresh();
   bool IsTrackingReady() const;
   bool IsRenderReady() const;
   ovrSession Get();
   void StartPresentation(const IntSize& aSize);
   void StopPresentation();
@@ -51,24 +52,24 @@ public:
   ovrTextureSwapChain GetSwapChain();
 
 private:
   PRLibrary* mOvrLib;
   ovrSession mSession;
   ovrInitFlags mInitFlags;
   ovrTextureSwapChain mTextureSet;
   nsTArray<RefPtr<layers::CompositingRenderTargetD3D11>> mRenderTargets;
-  bool mPresenting;
   IntSize mPresentationSize;
   RefPtr<ID3D11Device> mDevice;
   // The timestamp of the last time Oculus set ShouldQuit to true.
   TimeStamp mLastShouldQuit;
   // The timestamp of the last ending presentation
   TimeStamp mLastPresentationEnd;
-  TimeStamp mPresentationStart;
+  VRTelemetry mTelemetry;
+  bool mPresenting;
 
   ~VROculusSession();
   void Uninitialize(bool aUnloadLib);
   bool Initialize(ovrInitFlags aFlags);
   bool LoadOvrLib();
   void UnloadOvrLib();
   bool StartSession();
   void StopSession();
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -263,32 +263,44 @@ VRDisplayOpenVR::GetSensorState()
 
 void
 VRDisplayOpenVR::StartPresentation()
 {
   if (mIsPresenting) {
     return;
   }
   mIsPresenting = true;
-  mPresentationStart = TimeStamp::Now();
+  mTelemetry.Clear();
+  mTelemetry.mPresentationStart = TimeStamp::Now();
+
+  ::vr::Compositor_CumulativeStats stats;
+  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
+  mTelemetry.mLastDroppedFrameCount = stats.m_nNumReprojectedFrames;
 }
 
 void
 VRDisplayOpenVR::StopPresentation()
 {
   if (!mIsPresenting) {
     return;
   }
 
   mVRCompositor->ClearLastSubmittedFrame();
 
   mIsPresenting = false;
+  const TimeDuration duration = TimeStamp::Now() - mTelemetry.mPresentationStart;
   Telemetry::Accumulate(Telemetry::WEBVR_USERS_VIEW_IN, 2);
-  Telemetry::AccumulateTimeDelta(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR,
-                                 mPresentationStart);
+  Telemetry::Accumulate(Telemetry::WEBVR_TIME_SPENT_VIEWING_IN_OPENVR,
+                        duration.ToMilliseconds());
+
+  ::vr::Compositor_CumulativeStats stats;
+  mVRCompositor->GetCumulativeStats(&stats, sizeof(::vr::Compositor_CumulativeStats));
+  const uint32_t droppedFramesPerSec = (stats.m_nNumReprojectedFrames -
+                                        mTelemetry.mLastDroppedFrameCount) / duration.ToSeconds();
+  Telemetry::Accumulate(Telemetry::WEBVR_DROPPED_FRAMES_IN_OPENVR, droppedFramesPerSec);
 }
 
 bool
 VRDisplayOpenVR::SubmitFrame(void* aTextureHandle,
                              ::vr::ETextureType aTextureType,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -57,17 +57,17 @@ protected:
   virtual ~VRDisplayOpenVR();
   void Destroy();
 
   // not owned by us; global from OpenVR
   ::vr::IVRSystem *mVRSystem;
   ::vr::IVRChaperone *mVRChaperone;
   ::vr::IVRCompositor *mVRCompositor;
 
-  TimeStamp mPresentationStart;
+  VRTelemetry mTelemetry;
   bool mIsPresenting;
 
   void UpdateStageParameters();
   void PollEvents();
   bool SubmitFrame(void* aTextureHandle,
                    ::vr::ETextureType aTextureType,
                    const IntSize& aSize,
                    const gfx::Rect& aLeftEyeRect,
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -13555,16 +13555,38 @@
     "bug_numbers": [1306156],
     "expires_in_version": "never",
     "kind": "exponential",
     "high": 1200000,
     "n_buckets": 100,
     "releaseChannelCollection": "opt-out",
     "description": "The amount of time spent(ms) of a session for viewing content in OpenVR."
   },
+  "WEBVR_DROPPED_FRAMES_IN_OCULUS": {
+    "record_in_processes": ["main", "gpu"],
+    "alert_emails": ["dmu@mozilla.com"],
+    "bug_numbers": [1392476],
+    "expires_in_version": "never",
+    "kind": "linear",
+    "high": 200,
+    "n_buckets": 100,
+    "releaseChannelCollection": "opt-out",
+    "description": "The average number of dropped frames per sec in Oculus, sent when user exits WebVR content."
+  },
+  "WEBVR_DROPPED_FRAMES_IN_OPENVR": {
+    "record_in_processes": ["main", "gpu"],
+    "alert_emails": ["dmu@mozilla.com"],
+    "bug_numbers": [1392476],
+    "expires_in_version": "never",
+    "kind": "linear",
+    "high": 200,
+    "n_buckets": 100,
+    "releaseChannelCollection": "opt-out",
+    "description": "The average number of dropped frames per sec in OpenVR, sent when user exits WebVR content."
+  },
   "URLCLASSIFIER_UI_EVENTS": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["seceng-telemetry@mozilla.com", "francois@mozilla.com"],
     "bug_numbers": [1375277],
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 64,
     "description": "URL CLassifier-related (aka Safe Browsing) UI events. See nsIUrlClassifierUITelemetry.idl for the specific values."