Bug 963821 - Port FPS counter to the Compositor API. r=bas
authorBenoit Girard <b56girard@gmail.com>
Mon, 10 Feb 2014 17:14:11 -0500
changeset 168074 058f4ed4d33b49465ab9cc83ab85a760ec3578e1
parent 168073 618319a4d21dac9f6467835207770b3bf97f5ca6
child 168075 b5be94737a83ce805dcb6ca08773c391fb723bb7
push id39640
push userb56girard@gmail.com
push dateTue, 11 Feb 2014 15:21:23 +0000
treeherdermozilla-inbound@058f4ed4d33b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs963821
milestone30.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
Bug 963821 - Port FPS counter to the Compositor API. r=bas
gfx/layers/Compositor.h
gfx/layers/basic/BasicCompositor.h
gfx/layers/composite/FPSCounter.h
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
gfx/layers/d3d11/CompositorD3D11.h
gfx/layers/d3d9/CompositorD3D9.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/FPSCounter.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -403,23 +403,16 @@ public:
   }
   void SetCompositorID(uint32_t aID)
   {
     MOZ_ASSERT(mCompositorID == 0, "The compositor ID must be set only once.");
     mCompositorID = aID;
   }
 
   /**
-   * Notify the compositor that a layers transaction has occured. This is only
-   * used for FPS information at the moment.
-   * XXX: surely there is a better way to do this?
-   */
-  virtual void NotifyLayersTransaction() = 0;
-
-  /**
    * Notify the compositor that composition is being paused. This allows the
    * compositor to temporarily release any resources.
    * Between calling Pause and Resume, compositing may fail.
    */
   virtual void Pause() {}
   /**
    * Notify the compositor that composition is being resumed. The compositor
    * regain any resources it requires for compositing.
@@ -448,16 +441,27 @@ public:
    * thread at the same time. The backend type in use can be checked with this
    * static method. We need this for creating texture clients/hosts etc. when we
    * don't have a reference to a Compositor.
    *
    * This can only be used from the compositor thread!
    */
   static LayersBackend GetBackend();
 
+  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;
+  }
+
 protected:
   void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -109,18 +109,16 @@ public:
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
   }
 
   virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) { }
 
   virtual void PrepareViewport(const gfx::IntSize& aSize,
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE { }
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE { }
-
   virtual const char* Name() const { return "Basic"; }
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   gfx::DrawTarget *GetDrawTarget() { return mDrawTarget; }
 
 private:
   // Widget associated with this compositor
rename from gfx/layers/opengl/FPSCounter.h
rename to gfx/layers/composite/FPSCounter.h
--- a/gfx/layers/opengl/FPSCounter.h
+++ b/gfx/layers/composite/FPSCounter.h
@@ -14,16 +14,17 @@
 #include "VBOArena.h"                   // for gl::VBOArena
 
 namespace mozilla {
 namespace gl {
 class GLContext;
 }
 namespace layers {
 
+class DataTextureSource;
 class ShaderProgramOGL;
 
 const double kFpsWindowMs = 250.0;
 const size_t kNumFrameTimeStamps = 16;
 struct FPSCounter {
   FPSCounter() : mCurrentFrameIndex(0) {
       mFrames.SetLength(kNumFrameTimeStamps);
   }
@@ -66,26 +67,27 @@ private:
     if (realWindowSecs == 0.0 || numFramesDrawnInWindow == 1) {
       return 0.0;
     }
     return double(numFramesDrawnInWindow - 1) / realWindowSecs;
   }
 };
 
 struct FPSState {
-  GLuint mTexture;
   FPSCounter mCompositionFps;
   FPSCounter mTransactionFps;
-  gl::VBOArena mVBOs;
 
-  FPSState() : mTexture(0) { }
+  FPSState() {}
 
-  void DrawFPS(TimeStamp, unsigned, gl::GLContext*, ShaderProgramOGL*);
+  void DrawFPS(TimeStamp, unsigned, Compositor* aCompositor);
 
   void NotifyShadowTreeTransaction() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
+
+private:
+  RefPtr<DataTextureSource> mFPSTextureSource;
 };
 
 }
 }
 
 #endif // mozilla_layers_opengl_FPSCounter_h_
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -6,16 +6,17 @@
 #include "LayerManagerComposite.h"
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint16_t, uint32_t
 #include "CanvasLayerComposite.h"       // for CanvasLayerComposite
 #include "ColorLayerComposite.h"        // for ColorLayerComposite
 #include "Composer2D.h"                 // for Composer2D
 #include "CompositableHost.h"           // for CompositableHost
 #include "ContainerLayerComposite.h"    // for ContainerLayerComposite, etc
+#include "FPSCounter.h"                 // for FPSState, FPSCounter
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "GeckoProfiler.h"              // for profiler_set_frame_number, etc
 #include "ImageLayerComposite.h"        // for ImageLayerComposite
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "ThebesLayerComposite.h"       // for ThebesLayerComposite
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "Units.h"                      // for ScreenIntRect
 #include "gfx2DGlue.h"                  // for ToMatrix4x4
@@ -297,48 +298,139 @@ LayerManagerComposite::RootLayer() const
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return nullptr;
   }
 
   return ToLayerComposite(mRoot);
 }
 
+// Size of the builtin font.
+static const float FontHeight = 7.f;
+static const float FontWidth = 4.f;
+static const float FontStride = 4.f;
+
+// Scale the font when drawing it to the viewport for better readability.
+static const float FontScaleX = 2.f;
+static const float FontScaleY = 3.f;
+
+static void DrawDigits(unsigned int aValue,
+		       int aOffsetX, int aOffsetY,
+                       Compositor* aCompositor,
+		       EffectChain& aEffectChain)
+{
+  if (aValue > 999) {
+    aValue = 999;
+  }
+
+  unsigned int divisor = 100;
+  float textureWidth = FontWidth * 10;
+  gfx::Float opacity = 1;
+  gfx::Matrix4x4 transform;
+  transform.Scale(FontScaleX, FontScaleY, 1);
+
+  for (size_t n = 0; n < 3; ++n) {
+    unsigned int digit = aValue % (divisor * 10) / divisor;
+    divisor /= 10;
+
+    RefPtr<TexturedEffect> texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
+    texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f);
+
+    Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
+    Rect clipRect = Rect(0, 0, 300, 100);
+    aCompositor->DrawQuad(drawRect, clipRect,
+	aEffectChain, opacity, transform);
+  }
+}
+
+void FPSState::DrawFPS(TimeStamp aNow,
+                       unsigned int aFillRatio,
+                       Compositor* aCompositor)
+{
+  if (!mFPSTextureSource) {
+    const char *text =
+      "                                        "
+      " XXX XX  XXX XXX X X XXX XXX XXX XXX XXX"
+      " X X  X    X   X X X X   X     X X X X X"
+      " X X  X  XXX XXX XXX XXX XXX   X XXX XXX"
+      " X X  X  X     X   X   X X X   X X X   X"
+      " XXX XXX XXX XXX   X XXX XXX   X XXX   X"
+      "                                        ";
+
+    // Convert the text encoding above to RGBA.
+    int w = FontWidth * 10;
+    int h = FontHeight;
+    uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
+    for (int i = 0; i < h; i++) {
+      for (int j = 0; j < w; j++) {
+        uint32_t purple = 0xfff000ff;
+        uint32_t white  = 0xffffffff;
+        buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white;
+      }
+    }
+
+   int bytesPerPixel = 4;
+    RefPtr<DataSourceSurface> fpsSurface = Factory::CreateWrappingDataSourceSurface(
+      reinterpret_cast<uint8_t*>(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
+    mFPSTextureSource = aCompositor->CreateDataTextureSource();
+    mFPSTextureSource->Update(fpsSurface);
+  }
+
+  EffectChain effectChain;
+  effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT);
+
+  unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
+  unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
+
+  DrawDigits(fps, 0, 0, aCompositor, effectChain);
+  DrawDigits(txnFps, FontWidth * 4, 0, aCompositor, effectChain);
+  DrawDigits(aFillRatio, FontWidth * 8, 0, aCompositor, effectChain);
+}
+
 static uint16_t sFrameCount = 0;
 void
 LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds)
 {
-  if (!gfxPlatform::DrawFrameCounter()) {
-    return;
+  if (gfxPlatform::GetPrefLayersDrawFPS()) {
+    if (!mFPS) {
+      mFPS = new FPSState();
+    }
+
+    float fillRatio = mCompositor->GetFillRatio();
+    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mCompositor);
+  } else {
+    mFPS = nullptr;
   }
 
-  profiler_set_frame_number(sFrameCount);
+  if (gfxPlatform::DrawFrameCounter()) {
+    profiler_set_frame_number(sFrameCount);
 
-  uint16_t frameNumber = sFrameCount;
-  const uint16_t bitWidth = 3;
-  float opacity = 1.0;
-  gfx::Rect clip(0,0, bitWidth*16, bitWidth);
-  for (size_t i = 0; i < 16; i++) {
+    uint16_t frameNumber = sFrameCount;
+    const uint16_t bitWidth = 3;
+    float opacity = 1.0;
+    gfx::Rect clip(0,0, bitWidth*16, bitWidth);
+    for (size_t i = 0; i < 16; i++) {
 
-    gfx::Color bitColor;
-    if ((frameNumber >> i) & 0x1) {
-      bitColor = gfx::Color(0, 0, 0, 1.0);
-    } else {
-      bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0);
+      gfx::Color bitColor;
+      if ((frameNumber >> i) & 0x1) {
+        bitColor = gfx::Color(0, 0, 0, 1.0);
+      } else {
+        bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0);
+      }
+      EffectChain effects;
+      effects.mPrimaryEffect = new EffectSolidColor(bitColor);
+      mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth),
+                            clip,
+                            effects,
+                            opacity,
+                            gfx::Matrix4x4());
     }
-    EffectChain effects;
-    effects.mPrimaryEffect = new EffectSolidColor(bitColor);
-    mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth),
-                          clip,
-                          effects,
-                          opacity,
-                          gfx::Matrix4x4());
+    // We intentionally overflow at 2^16.
+    sFrameCount++;
   }
-  // We intentionally overflow at 2^16.
-  sFrameCount++;
 }
 
 void
 LayerManagerComposite::Render()
 {
   PROFILER_LABEL("LayerManagerComposite", "Render");
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
@@ -347,17 +439,21 @@ LayerManagerComposite::Render()
 
   if (gfxPlatform::GetPrefLayersDump()) {
     this->Dump();
   }
 
   /** Our more efficient but less powerful alter ego, if one is available. */
   nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
 
-  if (composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
+  if (mFPS && composer2D && composer2D->TryRender(mRoot, mWorldMatrix)) {
+    double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
+    if (gfxPlatform::GetPrefLayersDrawFPS()) {
+      printf_stderr("HWComposer: FPS is %g\n", fps);
+    }
     mCompositor->EndFrameForExternalComposition(mWorldMatrix);
     return;
   }
 
   {
     PROFILER_LABEL("LayerManagerComposite", "PreRender");
     if (!mCompositor->GetWidget()->PreRender(this)) {
       return;
@@ -782,16 +878,24 @@ LayerComposite::Destroy()
 
 bool
 LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize &aSize)
 {
   return mCompositor->CanUseCanvasLayerForSize(gfx::IntSize(aSize.width,
                                                             aSize.height));
 }
 
+void
+LayerManagerComposite::NotifyShadowTreeTransaction()
+{
+  if (mFPS) {
+    mFPS->NotifyShadowTreeTransaction();
+  }
+}
+
 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
 
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -56,16 +56,17 @@ class ContainerLayerComposite;
 class EffectChain;
 class ImageLayer;
 class ImageLayerComposite;
 class LayerComposite;
 class RefLayerComposite;
 class SurfaceDescriptor;
 class ThebesLayerComposite;
 class TiledLayerComposer;
+struct FPSState;
 
 class LayerManagerComposite : public LayerManager
 {
 public:
   LayerManagerComposite(Compositor* aCompositor);
   ~LayerManagerComposite();
   
   virtual void Destroy() MOZ_OVERRIDE;
@@ -219,16 +220,18 @@ public:
   /**
    * LayerManagerComposite provides sophisticated debug overlays
    * that can request a next frame.
    */
   bool DebugOverlayWantsNextFrame() { return mDebugOverlayWantsNextFrame; }
   void SetDebugOverlayWantsNextFrame(bool aVal)
   { mDebugOverlayWantsNextFrame = aVal; }
 
+  void NotifyShadowTreeTransaction();
+
 private:
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
   nsIntRect mRenderBounds;
 
   /** Current root layer. */
   LayerComposite* RootLayer() const;
 
@@ -251,23 +254,24 @@ private:
   /**
    * Render debug overlays such as the FPS/FrameCounter above the frame.
    */
   void RenderDebugOverlay(const gfx::Rect& aBounds);
 
   void WorldTransformRect(nsIntRect& aRect);
 
   RefPtr<Compositor> mCompositor;
+  nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
 
   gfx::Matrix mWorldMatrix;
+  nsIntRegion mInvalidRegion;
+  nsAutoPtr<FPSState> mFPS;
 
   bool mInTransaction;
   bool mIsCompositorReady;
-  nsIntRegion mInvalidRegion;
-  nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
   bool mDebugOverlayWantsNextFrame;
 };
 
 /**
  * Composite layers are for use with OMTC on the compositor thread only. There
  * must be corresponding Basic layers on the content thread. For composite
  * layers, the layer manager only maintains the layer tree, all rendering is
  * done by a Compositor (see Compositor.h). As such, composite layers are
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -131,18 +131,16 @@ public:
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D 11"; }
 #endif
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE { }
-
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   ID3D11Device* GetDevice() { return mDevice; }
 
 private:
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
   void VerifyBufferSize();
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -78,18 +78,16 @@ public:
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D9"; }
 #endif
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE {}
-
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   IDirect3DDevice9* device() const
   {
     return mDeviceManager
            ? mDeviceManager->device()
            : nullptr;
   }
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -510,17 +510,17 @@ void
 CompositorParent::NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint, bool aScheduleComposite)
 {
   if (mApzcTreeManager &&
       mLayerManager &&
       mLayerManager->GetRoot()) {
     AutoResolveRefLayers resolve(mCompositionManager);
     mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(), aIsFirstPaint, aId);
 
-    mCompositor->NotifyLayersTransaction();
+    mLayerManager->NotifyShadowTreeTransaction();
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
 }
 
 // Used when layout.frame_rate is -1. Needs to be kept in sync with
 // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
@@ -726,17 +726,17 @@ CompositorParent::ShadowLayersUpdated(La
     SetShadowProperties(root);
     if (mIsTesting) {
       mCompositionManager->TransformShadowTree(mTestTime);
     }
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
-  mCompositor->NotifyLayersTransaction();
+  mLayerManager->NotifyShadowTreeTransaction();
 }
 
 void
 CompositorParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints)
 {
   NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager");
   NS_ASSERTION(!mCompositor,   "Already initialised mCompositor");
 
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -2,17 +2,16 @@
  * 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 "CompositorOGL.h"
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint8_t
 #include <stdlib.h>                     // for free, malloc
-#include "FPSCounter.h"                 // for FPSState, FPSCounter
 #include "GLContextProvider.h"          // for GLContextProvider
 #include "GLContext.h"                  // for GLContext
 #include "GLUploadHelpers.h"
 #include "Layers.h"                     // for WriteSnapshotToDumpFile
 #include "LayerScope.h"                 // for LayerScope
 #include "gfx2DGlue.h"                  // for ThebesFilter
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxASurface.h"                // for gfxASurface, etc
@@ -130,122 +129,16 @@ DrawQuads(GLContext *aGLContext,
   aGLContext->fDisableVertexAttribArray(vertAttribIndex);
   if (texCoords) {
     aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   }
 
   aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
-// Size of the builtin font.
-static const float FontHeight = 7.f;
-static const float FontWidth = 5.f;
-static const float FontStride = 4.f;
-
-// Scale the font when drawing it to the viewport for better readability.
-static const float FontScaleX = 2.f;
-static const float FontScaleY = 3.f;
-
-// Size of the font texture (POT).
-static const size_t FontTextureWidth = 64;
-static const size_t FontTextureHeight = 8;
-
-static void
-AddDigits(RectTriangles &aRects,
-          const gfx::IntSize aViewportSize,
-          unsigned int aOffset,
-          unsigned int aValue)
-{
-  unsigned int divisor = 100;
-  for (size_t n = 0; n < 3; ++n) {
-    gfxRect d(aOffset * FontWidth, 0.f, FontWidth, FontHeight);
-    d.Scale(FontScaleX / aViewportSize.width, FontScaleY / aViewportSize.height);
-
-    unsigned int digit = aValue % (divisor * 10) / divisor;
-    gfxRect t(digit * FontStride, 0.f, FontWidth, FontHeight);
-    t.Scale(1.f / FontTextureWidth, 1.f / FontTextureHeight);
-
-    aRects.addRect(d.x, d.y, d.x + d.width, d.y + d.height,
-                   t.x, t.y, t.x + t.width, t.y + t.height,
-                   false);
-    divisor /= 10;
-    ++aOffset;
-  }
-}
-
-void
-FPSState::DrawFPS(TimeStamp aNow,
-                  unsigned int aFillRatio,
-                  GLContext* aContext,
-                  ShaderProgramOGL* aProgram)
-{
-  if (!mTexture) {
-    // Bind the number of textures we need, in this case one.
-    aContext->fGenTextures(1, &mTexture);
-    aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
-    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
-
-    const char *text =
-      "                                         "
-      " XXX XX  XXX XXX X X XXX XXX XXX XXX XXX "
-      " X X  X    X   X X X X   X     X X X X X "
-      " X X  X  XXX XXX XXX XXX XXX   X XXX XXX "
-      " X X  X  X     X   X   X X X   X X X   X "
-      " XXX XXX XXX XXX   X XXX XXX   X XXX   X "
-      "                                         ";
-
-    // Convert the text encoding above to RGBA.
-    uint32_t* buf = (uint32_t *) malloc(64 * 8 * sizeof(uint32_t));
-    for (int i = 0; i < 7; i++) {
-      for (int j = 0; j < 41; j++) {
-        uint32_t purple = 0xfff000ff;
-        uint32_t white  = 0xffffffff;
-        buf[i * 64 + j] = (text[i * 41 + j] == ' ') ? purple : white;
-      }
-    }
-    aContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
-    free(buf);
-  }
-
-  mVBOs.Reset();
-
-  GLint viewport[4];
-  aContext->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
-  gfx::IntSize viewportSize(viewport[2], viewport[3]);
-
-  unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
-  unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
-
-  RectTriangles rects;
-  AddDigits(rects, viewportSize, 0, fps);
-  AddDigits(rects, viewportSize, 4, txnFps);
-  AddDigits(rects, viewportSize, 8, aFillRatio);
-
-  // Turn necessary features on
-  aContext->fEnable(LOCAL_GL_BLEND);
-  aContext->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
-
-  aContext->fActiveTexture(LOCAL_GL_TEXTURE0);
-  aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
-  aProgram->Activate();
-  aProgram->SetTextureUnit(0);
-  aProgram->SetLayerQuadRect(gfx::Rect(0.f, 0.f, viewport[2], viewport[3]));
-  aProgram->SetLayerOpacity(1.f);
-  aProgram->SetTextureTransform(Matrix4x4());
-  aProgram->SetLayerTransform(Matrix4x4());
-  aProgram->SetRenderOffset(0, 0);
-
-  aContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
-                               LOCAL_GL_ONE, LOCAL_GL_ZERO);
-
-  DrawQuads(aContext, mVBOs, aProgram, rects);
-}
-
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
@@ -322,21 +215,16 @@ CompositorOGL::GetTemporaryTexture(GLenu
 void
 CompositorOGL::Destroy()
 {
   if (gl() && gl()->MakeCurrent()) {
     if (mTextures.Length() > 0) {
       gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]);
     }
     mVBOs.Flush(gl());
-    if (mFPS) {
-      if (mFPS->mTexture > 0)
-        gl()->fDeleteTextures(1, &mFPS->mTexture);
-      mFPS->mVBOs.Flush(gl());
-    }
   }
   mTextures.SetLength(0);
   if (!mDestroyed) {
     mDestroyed = true;
     CleanupResources();
   }
 }
 
@@ -364,25 +252,16 @@ CompositorOGL::CleanupResources()
   if (mQuadVBO) {
     ctx->fDeleteBuffers(1, &mQuadVBO);
     mQuadVBO = 0;
   }
 
   mGLContext = nullptr;
 }
 
-// Impl of a a helper-runnable's "Run" method, used in Initialize()
-NS_IMETHODIMP
-CompositorOGL::ReadDrawFPSPref::Run()
-{
-  // NOTE: This must match the code in Initialize()'s NS_IsMainThread check.
-  Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
-  return NS_OK;
-}
-
 bool
 CompositorOGL::Initialize()
 {
   ScopedGfxFeatureReporter reporter("GL Layers", true);
 
   // Do not allow double initialization
   NS_ABORT_IF_FALSE(mGLContext == nullptr, "Don't reinitialize CompositorOGL");
 
@@ -540,24 +419,16 @@ CompositorOGL::Initialize()
     msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
     if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
       msg += NS_LITERAL_STRING("TEXTURE_2D");
     else
       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
     console->LogStringMessage(msg.get());
   }
 
-  if (NS_IsMainThread()) {
-    // NOTE: This must match the code in ReadDrawFPSPref::Run().
-    Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
-  } else {
-    // We have to dispatch an event to the main thread to read the pref.
-    NS_DispatchToMainThread(new ReadDrawFPSPref());
-  }
-
   reporter.SetSuccessful();
   return true;
 }
 
 // |aTextureTransform| is the texture transform that will be set on
 // aProg, possibly multiplied with another texture transform of our
 // own.
 // |aTexCoordRect| is the rectangle from the texture that we want to
@@ -751,18 +622,16 @@ GetFrameBufferInternalFormat(GLContext* 
                              nsIWidget* aWidget)
 {
   if (aFrameBuffer == 0) { // default framebuffer
     return aWidget->GetGLFrameBufferFormat();
   }
   return LOCAL_GL_RGBA;
 }
 
-bool CompositorOGL::sDrawFPS = false;
-
 /*
  * Returns a size that is larger than and closest to aSize where both
  * width and height are powers of two.
  * If the OpenGL setup is capable of using non-POT textures, then it
  * will just return aSize.
  */
 static IntSize
 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
@@ -1420,47 +1289,23 @@ CompositorOGL::EndFrame()
     CopyToTarget(mTarget, mCurrentRenderTarget->GetTransform());
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     mCurrentRenderTarget = nullptr;
     return;
   }
 
   mCurrentRenderTarget = nullptr;
 
-  if (sDrawFPS && !mFPS) {
-    mFPS = new FPSState();
-  } else if (!sDrawFPS && mFPS) {
-    mFPS = nullptr;
-  }
-
-  if (mFPS) {
-    float fillRatio = 0;
-    if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
-      fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
-      if (fillRatio > 999.0f)
-        fillRatio = 999.0f;
-    }
-    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(RGBXLayerProgramType));
-  }
-
   mGLContext->SwapBuffers();
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
 {
-  if (sDrawFPS) {
-    if (!mFPS) {
-      mFPS = new FPSState();
-    }
-    double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
-    printf_stderr("HWComposer: FPS is %g\n", fps);
-  }
-
   // This lets us reftest and screenshot content rendered externally
   if (mTarget) {
     MakeCurrent();
     CopyToTarget(mTarget, aTransform);
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   }
 }
 
@@ -1527,39 +1372,16 @@ CompositorOGL::CopyToTarget(DrawTarget *
   Matrix oldMatrix = aTarget->GetTransform();
   aTarget->SetTransform(glToCairoTransform);
   Rect floatRect = Rect(rect.x, rect.y, rect.width, rect.height);
   aTarget->DrawSurface(source, floatRect, floatRect, DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE));
   aTarget->SetTransform(oldMatrix);
   aTarget->Flush();
 }
 
-double
-CompositorOGL::AddFrameAndGetFps(const TimeStamp& timestamp)
-{
-  if (sDrawFPS) {
-    if (!mFPS) {
-      mFPS = new FPSState();
-    }
-    double fps = mFPS->mCompositionFps.AddFrameAndGetFps(timestamp);
-
-    return fps;
-  }
-
-  return 0.;
-}
-
-void
-CompositorOGL::NotifyLayersTransaction()
-{
-  if (mFPS) {
-    mFPS->NotifyShadowTreeTransaction();
-  }
-}
-
 void
 CompositorOGL::Pause()
 {
 #ifdef MOZ_WIDGET_ANDROID
   if (!gl() || gl()->IsDestroyed())
     return;
 
   // ReleaseSurface internally calls MakeCurrent.
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -46,17 +46,16 @@ namespace layers {
 
 class CompositingRenderTarget;
 class CompositingRenderTargetOGL;
 class DataTextureSource;
 class GLManagerCompositor;
 class TextureSource;
 struct Effect;
 struct EffectChain;
-struct FPSState;
 
 class CompositorOGL : public Compositor
 {
   typedef mozilla::gl::GLContext GLContext;
   typedef ShaderProgramType ProgramType;
   
   friend class GLManagerCompositor;
 
@@ -146,18 +145,16 @@ public:
   virtual void PrepareViewport(const gfx::IntSize& aSize,
                                const gfx::Matrix& aWorldTransform) MOZ_OVERRIDE;
 
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "OGL"; }
 #endif // MOZ_DUMP_PAINTING
 
-  virtual void NotifyLayersTransaction() MOZ_OVERRIDE;
-
   virtual void Pause() MOZ_OVERRIDE;
   virtual bool Resume() MOZ_OVERRIDE;
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   GLContext* gl() const { return mGLContext; }
   ShaderProgramType GetFBOLayerProgramType() const {
     return mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB ?
@@ -192,22 +189,16 @@ private:
   nsIntSize mWidgetSize;
   nsRefPtr<GLContext> mGLContext;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
   ScreenPoint mRenderOffset;
 
-  /** Helper-class used by Initialize **/
-  class ReadDrawFPSPref MOZ_FINAL : public nsRunnable {
-  public:
-    NS_IMETHOD Run() MOZ_OVERRIDE;
-  };
-
   already_AddRefed<mozilla::gl::GLContext> CreateContext();
 
   /** Shader Programs */
   struct ShaderProgramVariations {
     nsAutoTArray<nsAutoPtr<ShaderProgramOGL>, NumMaskTypes> mVariations;
     ShaderProgramVariations() {
       MOZ_COUNT_CTOR(ShaderProgramVariations);
       mVariations.SetLength(NumMaskTypes);
@@ -321,34 +312,28 @@ private:
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    * Does not restore the target FBO, so only call from EndFrame.
    */
   void CopyToTarget(gfx::DrawTarget* aTarget, const gfx::Matrix& aWorldMatrix);
 
   /**
-   * Records the passed frame timestamp and returns the current estimated FPS.
-   */
-  double AddFrameAndGetFps(const TimeStamp& timestamp);
-
-  /**
    * Implements the flipping of the y-axis to convert from layers/compositor
    * coordinates to OpenGL coordinates.
    *
    * Indeed, the only coordinate system that OpenGL knows has the y-axis
    * pointing upwards, but the layers/compositor coordinate system has the
    * y-axis pointing downwards, for good reason as Web pages are typically
    * scrolled downwards. So, some flipping has to take place; FlippedY does it.
    */
   GLint FlipY(GLint y) const { return mHeight - y; }
 
   bool mDestroyed;
 
-  nsAutoPtr<FPSState> mFPS;
   // Textures used for direct texturing of buffers like gralloc.
   // The index of the texture in this array must correspond to the texture unit.
   nsTArray<GLuint> mTextures;
   static bool sDrawFPS;
 
   /**
    * Height of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation.
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2058,16 +2058,17 @@ gfxPlatform::GetOrientationSyncMillis() 
  */
 static bool sPrefLayersOffMainThreadCompositionEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionTestingEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionForceEnabled = false;
 static bool sPrefLayersAccelerationForceEnabled = false;
 static bool sPrefLayersAccelerationDisabled = false;
 static bool sPrefLayersPreferOpenGL = false;
 static bool sPrefLayersPreferD3D9 = false;
+static bool sPrefLayersDrawFPS = false;
 static bool sPrefLayersDump = false;
 static bool sPrefLayersScrollGraph = false;
 static bool sPrefLayersEnableTiles = false;
 static bool sLayersSupportsD3D9 = false;
 static int  sPrefLayoutFrameRate = -1;
 static int  sPrefLayersCompositionFrameRate = -1;
 static bool sBufferRotationEnabled = false;
 static bool sComponentAlphaEnabled = true;
@@ -2088,16 +2089,17 @@ InitLayersAccelerationPrefs()
 
     sPrefLayersOffMainThreadCompositionEnabled = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
     sPrefLayersOffMainThreadCompositionTestingEnabled = Preferences::GetBool("layers.offmainthreadcomposition.testing.enabled", false);
     sPrefLayersOffMainThreadCompositionForceEnabled = Preferences::GetBool("layers.offmainthreadcomposition.force-enabled", false);
     sPrefLayersAccelerationForceEnabled = Preferences::GetBool("layers.acceleration.force-enabled", false);
     sPrefLayersAccelerationDisabled = Preferences::GetBool("layers.acceleration.disabled", false);
     sPrefLayersPreferOpenGL = Preferences::GetBool("layers.prefer-opengl", false);
     sPrefLayersPreferD3D9 = Preferences::GetBool("layers.prefer-d3d9", false);
+    sPrefLayersDrawFPS = Preferences::GetBool("layers.acceleration.draw-fps", false);
     sPrefLayersDump = Preferences::GetBool("layers.dump", false);
     sPrefLayersScrollGraph = Preferences::GetBool("layers.scroll-graph", false);
     sPrefLayersEnableTiles = Preferences::GetBool("layers.enable-tiles", false);
     sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
     sPrefLayersCompositionFrameRate = Preferences::GetInt("layers.offmainthreadcomposition.frame-rate", -1);
     sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
     sComponentAlphaEnabled = Preferences::GetBool("layers.componentalpha.enabled", true);
     sPrefBrowserTabsRemote = BrowserTabsRemote();
@@ -2174,16 +2176,23 @@ gfxPlatform::GetPrefLayersPreferOpenGL()
 bool
 gfxPlatform::GetPrefLayersPreferD3D9()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersPreferD3D9;
 }
 
 bool
+gfxPlatform::GetPrefLayersDrawFPS()
+{
+  InitLayersAccelerationPrefs();
+  return sPrefLayersDrawFPS;
+}
+
+bool
 gfxPlatform::CanUseDirect3D9()
 {
   // this function is called from the compositor thread, so it is not
   // safe to init the prefs etc. from here.
   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
   return sLayersSupportsD3D9;
 }
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -508,16 +508,17 @@ public:
     static bool GetPrefLayersPreferOpenGL();
     static bool GetPrefLayersPreferD3D9();
     static bool CanUseDirect3D9();
     static int  GetPrefLayoutFrameRate();
     static int  GetPrefLayersCompositionFrameRate();
     static bool GetPrefLayersDump();
     static bool GetPrefLayersScrollGraph();
     static bool GetPrefLayersEnableTiles();
+    static bool GetPrefLayersDrawFPS();
 
     static bool OffMainThreadCompositionRequired();
 
     /**
      * Is it possible to use buffer rotation
      */
     static bool BufferRotationEnabled();
     static void DisableBufferRotation();