Bug 1014042 - Add compositor benchmark. r=jrmuizel
authorBenoit Girard <b56girard@gmail.com>
Wed, 21 May 2014 17:29:49 +0000
changeset 196797 344f0e4b126cb3846bc6945d6ee5b1dbe18970ea
parent 196770 3d4e5e80de4ad0ebd30617f58eace3d08e4af3c6
child 196798 9c4c4356afcebb6c69dc4ec14b52abaf4e365bde
push idunknown
push userunknown
push dateunknown
reviewersjrmuizel
bugs1014042
milestone32.0a1
Bug 1014042 - Add compositor benchmark. r=jrmuizel
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/ipc/CompositorBench.cpp
gfx/layers/ipc/CompositorBench.h
gfx/layers/moz.build
gfx/thebes/gfxPrefs.h
modules/libpref/src/init/all.js
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -33,16 +33,17 @@
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for IntSize, Point
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"          // for Color, SurfaceFormat
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
 #include "mozilla/layers/LayersTypes.h"  // for etc
+#include "ipc/CompositorBench.h"        // for CompositorBench
 #include "ipc/ShadowLayerUtils.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING, NS_RUNTIMEABORT, etc
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsPoint.h"                    // for nsIntPoint
@@ -402,16 +403,19 @@ LayerManagerComposite::Render()
     if (!mCompositor->GetWidget()->PreRender(this)) {
       return;
     }
   }
 
   nsIntRect clipRect;
   Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
   Rect actualBounds;
+
+  CompositorBench(mCompositor, bounds);
+
   if (mRoot->GetClipRect()) {
     clipRect = *mRoot->GetClipRect();
     WorldTransformRect(clipRect);
     Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
     mCompositor->BeginFrame(mInvalidRegion, &rect, mWorldMatrix, bounds, nullptr, &actualBounds);
   } else {
     gfx::Rect rect;
     mCompositor->BeginFrame(mInvalidRegion, nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBench.cpp
@@ -0,0 +1,248 @@
+/* -*- 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 "CompositorBench.h"
+
+#ifdef MOZ_COMPOSITOR_BENCH
+#include "mozilla/gfx/2D.h"
+#include "mozilla/layers/Compositor.h"
+#include "mozilla/layers/Effects.h"
+#include "mozilla/TimeStamp.h"
+#include "gfxColor.h"
+#include "gfxPrefs.h"
+#include <math.h>
+#include "GeckoProfiler.h"
+
+#define TEST_STEPS 1000
+#define DURATION_THRESHOLD 30
+#define THRESHOLD_ABORT_COUNT 5
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+static float SimplePseudoRandom(int aStep, int aCount) {
+  srand(aStep * 1000 + aCount);
+  return static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
+}
+
+class BenchTest {
+public:
+  BenchTest(const char* aTestName)
+    : mTestName(aTestName)
+  {}
+
+  virtual ~BenchTest() {}
+
+  virtual void Setup(Compositor* aCompositor, size_t aStep) {}
+  virtual void Teardown(Compositor* aCompositor) {}
+  virtual void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) = 0;
+
+  const char* ToString() { return mTestName; }
+private:
+  const char* mTestName;
+};
+
+class EffectSolidColorBench : public BenchTest {
+public:
+  EffectSolidColorBench()
+    : BenchTest("EffectSolidColorBench (clear frame with EffectSolidColor)")
+  {}
+
+  void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+    float red;
+    float tmp;
+    red = modf(aStep * 0.03f, &tmp);
+    EffectChain effects;
+    gfxRGBA color(red, 0.4f, 0.4f, 1.0f);
+    effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
+                                                             color.g,
+                                                             color.b,
+                                                             color.a));
+
+    const gfx::Rect& rect = aScreenRect;
+    const gfx::Rect& clipRect = aScreenRect;
+
+    float opacity = 1.f;
+
+    gfx::Matrix4x4 transform;
+    aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
+  }
+};
+
+class EffectSolidColorTrivialBench : public BenchTest {
+public:
+  EffectSolidColorTrivialBench()
+    : BenchTest("EffectSolidColorTrivialBench (10s 1x1 EffectSolidColor)")
+  {}
+
+  void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+    for (size_t i = 0; i < aStep * 10; i++) {
+      float red;
+      float tmp;
+      red = modf(i * 0.03f, &tmp);
+      EffectChain effects;
+      gfxRGBA color(red, 0.4f, 0.4f, 1.0f);
+      effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
+                                                               color.g,
+                                                               color.b,
+                                                               color.a));
+
+      const gfx::Rect& rect = gfx::Rect(i % (int)aScreenRect.width,
+                                        (int)(i / aScreenRect.height),
+                                        1, 1);
+      const gfx::Rect& clipRect = aScreenRect;
+
+      float opacity = 1.f;
+
+      gfx::Matrix transform2d;
+
+      gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
+
+      aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
+    }
+  }
+};
+
+class EffectSolidColorStressBench : public BenchTest {
+public:
+  EffectSolidColorStressBench()
+    : BenchTest("EffectSolidColorStressBench (10s various EffectSolidColor)")
+  {}
+
+  void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+    for (size_t i = 0; i < aStep * 10; i++) {
+      float red;
+      float tmp;
+      red = modf(i * 0.03f, &tmp);
+      EffectChain effects;
+      gfxRGBA color(red, 0.4f, 0.4f, 1.0f);
+      effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
+                                                               color.g,
+                                                               color.b,
+                                                               color.a));
+
+      const gfx::Rect& rect = gfx::Rect(aScreenRect.width * SimplePseudoRandom(i, 0),
+                                        aScreenRect.height * SimplePseudoRandom(i, 1),
+                                        aScreenRect.width * SimplePseudoRandom(i, 2),
+                                        aScreenRect.height * SimplePseudoRandom(i, 3));
+      const gfx::Rect& clipRect = aScreenRect;
+
+      float opacity = 0.3f;
+
+      gfx::Matrix transform2d;
+      transform2d = transform2d.Rotate(SimplePseudoRandom(i, 4) * 70.f);
+
+      gfx::Matrix4x4 transform = gfx::Matrix4x4::From2D(transform2d);
+
+      aCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
+    }
+  }
+};
+
+class UploadBench : public BenchTest {
+public:
+  UploadBench()
+    : BenchTest("Upload Bench (10s 256x256 upload)")
+  {}
+
+  uint32_t* mBuf;
+  RefPtr<DataSourceSurface> mSurface;
+  RefPtr<DataTextureSource> mTexture;
+
+  virtual void Setup(Compositor* aCompositor, size_t aStep) {
+    int bytesPerPixel = 4;
+    int w = 256;
+    int h = 256;
+    mBuf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
+
+    mSurface = Factory::CreateWrappingDataSourceSurface(
+      reinterpret_cast<uint8_t*>(mBuf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
+    mTexture = aCompositor->CreateDataTextureSource();
+  }
+
+  virtual void Teardown(Compositor* aCompositor) {
+    mSurface = nullptr;
+    mTexture = nullptr;
+    free(mBuf);
+  }
+
+  void DrawFrame(Compositor* aCompositor, const gfx::Rect& aScreenRect, size_t aStep) {
+    for (size_t i = 0; i < aStep * 10; i++) {
+      mTexture->Update(mSurface);
+    }
+  }
+};
+
+static void RunCompositorBench(Compositor* aCompositor, const gfx::Rect& aScreenRect)
+{
+  std::vector<BenchTest*> tests;
+
+  tests.push_back(new EffectSolidColorBench());
+  tests.push_back(new EffectSolidColorTrivialBench());
+  tests.push_back(new EffectSolidColorStressBench());
+  tests.push_back(new UploadBench());
+
+  for (size_t i = 0; i < tests.size(); i++) {
+    BenchTest* test = tests[i];
+    std::vector<TimeDuration> results;
+    int testsOverThreshold = 0;
+    PROFILER_MARKER(test->ToString());
+    for (size_t j = 0; j < TEST_STEPS; j++) {
+      test->Setup(aCompositor, j);
+
+      TimeStamp start = TimeStamp::Now();
+      nsIntRect screenRect(aScreenRect.x, aScreenRect.y,
+                           aScreenRect.width, aScreenRect.height);
+      aCompositor->BeginFrame(
+        nsIntRect(screenRect.x, screenRect.y,
+                  screenRect.width, screenRect.height),
+        nullptr, gfx::Matrix(), aScreenRect);
+
+      test->DrawFrame(aCompositor, aScreenRect, j);
+
+      aCompositor->EndFrame();
+      results.push_back(TimeStamp::Now() - start);
+
+      if (results[j].ToMilliseconds() > DURATION_THRESHOLD) {
+        testsOverThreshold++;
+        if (testsOverThreshold == THRESHOLD_ABORT_COUNT) {
+          test->Teardown(aCompositor);
+          break;
+        }
+      } else {
+        testsOverThreshold = 0;
+      }
+      test->Teardown(aCompositor);
+    }
+
+    printf_stderr("%s\n", test->ToString());
+    printf_stderr("Run step, Time (ms)\n");
+    for (size_t j = 0; j < results.size(); j++) {
+      printf_stderr("%i,%f\n", j, (float)results[j].ToMilliseconds());
+    }
+    printf_stderr("\n", test->ToString());
+  }
+
+  for (size_t i = 0; i < tests.size(); i++) {
+    delete tests[i];
+  }
+}
+
+void CompositorBench(Compositor* aCompositor, const gfx::Rect& aScreenRect)
+{
+  static bool sRanBenchmark = false;
+  bool wantBenchmark = gfxPrefs::LayersBenchEnabled();
+  if (wantBenchmark && !sRanBenchmark) {
+    RunCompositorBench(aCompositor, aScreenRect);
+  }
+  sRanBenchmark = wantBenchmark;
+}
+
+}
+}
+#endif
+
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/CompositorBench.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* 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_layers_CompositorBench_h
+#define mozilla_layers_CompositorBench_h
+
+#include "mozilla/gfx/Rect.h"           // for Rect
+
+namespace mozilla {
+namespace layers {
+
+class Compositor;
+
+// Uncomment this line to rebuild with compositor bench.
+// #define MOZ_COMPOSITOR_BENCH
+
+#ifdef MOZ_COMPOSITOR_BENCH
+void CompositorBench(Compositor* aCompositor, const gfx::Rect& aScreenRect);
+#else
+static inline void CompositorBench(Compositor* aCompositor, const gfx::Rect& aScreenRect) {}
+#endif
+
+}
+}
+
+#endif
+
+
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -274,16 +274,17 @@ UNIFIED_SOURCES += [
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
     'CopyableCanvasLayer.cpp',
     'Effects.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
     'ipc/AsyncTransactionTracker.cpp',
     'ipc/CompositableTransactionParent.cpp',
+    'ipc/CompositorBench.cpp',
     'ipc/CompositorChild.cpp',
     'ipc/CompositorParent.cpp',
     'ipc/ImageBridgeChild.cpp',
     'ipc/ImageBridgeParent.cpp',
     'ipc/ISurfaceAllocator.cpp',
     'ipc/LayerTransactionChild.cpp',
     'ipc/LayerTransactionParent.cpp',
     'ipc/ShadowLayerChild.cpp',
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -159,16 +159,17 @@ private:
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-video.enabled",            AsyncVideoEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-video-oop.enabled",        AsyncVideoOOPEnabled, bool, false);
+  DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
   // If MOZ_GFX_OPTIMIZE_MOBILE is defined, we force component alpha off
   // and ignore the preference.
   DECL_GFX_PREF(Skip, "layers.componentalpha.enabled",         ComponentAlphaEnabled, bool, false);
 #else
   // If MOZ_GFX_OPTIMIZE_MOBILE is not defined, we actually take the
   // preference value, defaulting to true.
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3709,16 +3709,19 @@ pref("network.tcp.keepalive.retry_interv
 // Default maximum probe retransmissions.
 // Linux only; not configurable on Win and Mac; fixed at 10 and 8 respectively.
 #ifdef XP_UNIX && !defined(XP_MACOSX)
 pref("network.tcp.keepalive.probe_count", 4);
 #endif
 
 // Whether to disable acceleration for all widgets.
 pref("layers.acceleration.disabled", false);
+// Preference that when switched at runtime will run a series of benchmarks
+// and output the result to stderr.
+pref("layers.bench.enabled", false);
 
 // Whether to force acceleration on, ignoring blacklists.
 #ifdef ANDROID
 // bug 838603 -- on Android, accidentally blacklisting OpenGL layers
 // means a startup crash for everyone.
 pref("layers.acceleration.force-enabled", true);
 #else
 pref("layers.acceleration.force-enabled", false);