Allow GMs to be used as benchmarks. Make convex_poly_clip opt in.

R=reed@google.com

Author: bsalomon@google.com

Review URL: https://codereview.chromium.org/151843002

git-svn-id: http://skia.googlecode.com/svn/trunk@13279 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h
index bf44d2c..f1e317d 100644
--- a/bench/SkBenchmark.h
+++ b/bench/SkBenchmark.h
@@ -13,9 +13,13 @@
 #include "SkString.h"
 #include "SkTRegistry.h"
 
-#define DEF_BENCH(code) \
-static SkBenchmark* SK_MACRO_APPEND_LINE(F_)() { code; } \
-static BenchRegistry SK_MACRO_APPEND_LINE(R_)(SK_MACRO_APPEND_LINE(F_));
+#define DEF_BENCH(code)                                                 \
+namespace {                                                             \
+class SK_MACRO_APPEND_LINE(F_CLASS) : public SkBenchmarkFactory {       \
+    virtual SkBenchmark* operator()() const SK_OVERRIDE { code; }       \
+} SK_MACRO_APPEND_LINE(g_F_);                                           \
+BenchRegistry SK_MACRO_APPEND_LINE(g_R_)(&SK_MACRO_APPEND_LINE(g_F_));  \
+}
 
 /*
  *  With the above macros, you can register benches as follows (at the bottom
@@ -132,6 +136,13 @@
     typedef SkRefCnt INHERITED;
 };
 
-typedef SkTRegistry<SkBenchmark*(*)()> BenchRegistry;
+class SkBenchmarkFactory : public SkRefCnt {
+public:
+    // Creates a new SkBenchmark that is owned by the caller on each call.
+    virtual SkBenchmark* operator()() const = 0;
+    virtual ~SkBenchmarkFactory() {}
+};
+
+typedef SkTRegistry<SkBenchmarkFactory*> BenchRegistry;
 
 #endif
diff --git a/bench/SkGMBench.cpp b/bench/SkGMBench.cpp
new file mode 100644
index 0000000..e1d8124
--- /dev/null
+++ b/bench/SkGMBench.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkGMBench.h"
+
+SkGMBench::SkGMBench(skiagm::GM* gm) : fGM(gm) {
+    fName.printf("GM:%s", gm->shortName());
+}
+
+SkGMBench::~SkGMBench() { delete fGM; }
+
+const char* SkGMBench::onGetName() {
+    return fName.c_str();
+}
+
+bool SkGMBench::isSuitableFor(Backend backend) {
+    uint32_t flags = fGM->getFlags();
+    switch (backend) {
+        case kGPU_Backend:
+            return !(skiagm::GM::kSkipGPU_Flag & flags);
+        case kPDF_Backend:
+            return !(skiagm::GM::kSkipPDF_Flag & flags);
+        case kRaster_Backend:
+            // GM doesn't have an equivalent flag. If the GM has known issues with 565 then
+            // we skip it for ALL raster configs in bench.
+            return !(skiagm::GM::kSkip565_Flag & flags);
+        case kNonRendering_Backend:
+            return false;
+        default:
+            SkDEBUGFAIL("Unexpected backend type.");
+            return false;
+    }
+}
+
+void SkGMBench::onDraw(const int loops, SkCanvas* canvas) {
+    // Do we care about timing the draw of the background (once)?
+    // Does the GM ever rely on drawBackground to lazily compute something?
+    fGM->drawBackground(canvas);
+    for (int i = 0; i < loops; ++i) {
+        fGM->drawContent(canvas);
+    }
+}
+
+SkIPoint SkGMBench::onGetSize() {
+    SkISize size = fGM->getISize();
+    return SkIPoint::Make(size.fWidth, size.fHeight);
+}
diff --git a/bench/SkGMBench.h b/bench/SkGMBench.h
new file mode 100644
index 0000000..925a875
--- /dev/null
+++ b/bench/SkGMBench.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "gm.h"
+#include "SkCanvas.h"
+
+/**
+ * Runs a GM as a benchmark by repeatedly drawing the GM.
+ */
+class SkGMBench : public SkBenchmark {
+public:
+    // Constructor takes ownership of the GM param.
+    SkGMBench(skiagm::GM* gm);
+    virtual ~SkGMBench();
+
+protected:
+    virtual const char* onGetName() SK_OVERRIDE;
+    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE;
+    virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE;
+    virtual SkIPoint onGetSize() SK_OVERRIDE;
+
+private:
+    skiagm::GM* fGM;
+    SkString    fName;
+    typedef SkBenchmark INHERITED;
+};
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 12c9820..80aed1c 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -14,6 +14,7 @@
 #include "SkColorPriv.h"
 #include "SkCommandLineFlags.h"
 #include "SkDeferredCanvas.h"
+#include "SkGMBench.h"
 #include "SkGraphics.h"
 #include "SkImageEncoder.h"
 #include "SkOSFile.h"
@@ -32,6 +33,52 @@
 
 #include <limits>
 
+// Note that ~SkTDArray is not virtual. This inherits privately to bar using this as a SkTDArray*.
+class RefCntArray : private SkTDArray<SkRefCnt*> {
+public:
+    SkRefCnt** append() { return this->INHERITED::append(); }
+    ~RefCntArray() { this->unrefAll(); }
+private:
+    typedef SkTDArray<SkRefCnt*> INHERITED;
+};
+
+class GMBenchFactory : public SkBenchmarkFactory {
+public:
+    GMBenchFactory(const skiagm::GMRegistry* gmreg)
+    : fGMFactory(gmreg->factory()) {
+        fSelfRegistry = SkNEW_ARGS(BenchRegistry, (this));
+    }
+
+    virtual ~GMBenchFactory() { SkDELETE(fSelfRegistry); }
+
+    virtual SkBenchmark* operator()() const SK_OVERRIDE {
+        skiagm::GM* gm = fGMFactory(NULL);
+        return SkNEW_ARGS(SkGMBench, (gm));
+    }
+
+private:
+    skiagm::GMRegistry::Factory fGMFactory;
+    BenchRegistry*              fSelfRegistry;
+};
+
+static void register_gm_benches() {
+    static bool gOnce;
+    static RefCntArray gGMBenchFactories;
+
+    if (!gOnce) {
+        const skiagm::GMRegistry* gmreg = skiagm::GMRegistry::Head();
+        while (gmreg) {
+            skiagm::GM* gm = gmreg->factory()(NULL);
+            if (NULL != gm  && skiagm::GM::kAsBench_Flag & gm->getFlags()) {
+                *gGMBenchFactories.append() = SkNEW_ARGS(GMBenchFactory, (gmreg));
+            }
+            SkDELETE(gm);
+            gmreg = gmreg->next();
+        }
+        gOnce = true;
+    }
+}
+
 enum BenchMode {
     kNormal_BenchMode,
     kDeferred_BenchMode,
@@ -63,7 +110,7 @@
         if (fBench) {
             BenchRegistry::Factory f = fBench->factory();
             fBench = fBench->next();
-            return f();
+            return (*f)();
         }
         return NULL;
     }
@@ -295,6 +342,7 @@
 
 int tool_main(int argc, char** argv);
 int tool_main(int argc, char** argv) {
+    register_gm_benches();
     SkCommandLineFlags::Parse(argc, argv);
 #if SK_ENABLE_INST_COUNT
     if (FLAGS_leaks) {
diff --git a/gm/convexpolyclip.cpp b/gm/convexpolyclip.cpp
index db357bb..18b99a7 100644
--- a/gm/convexpolyclip.cpp
+++ b/gm/convexpolyclip.cpp
@@ -182,6 +182,10 @@
         }
     }
 
+    virtual uint32_t onGetFlags() const {
+        return kAsBench_Flag;
+    }
+
 private:
     SkTLList<SkPath> fPaths;
     SkBitmap         fBmp;
diff --git a/gm/gm.h b/gm/gm.h
index e69cfc0..bb20c9c 100644
--- a/gm/gm.h
+++ b/gm/gm.h
@@ -49,6 +49,8 @@
             kSkipPDFRasterization_Flag  = 1 << 8,
 
             kGPUOnly_Flag               = 1 << 9,
+
+            kAsBench_Flag               = 1 << 10, // Run the GM as a benchmark in the bench tool
         };
 
         void draw(SkCanvas*);
diff --git a/gyp/SampleApp.gyp b/gyp/SampleApp.gyp
index 43c5d89..5d71748 100644
--- a/gyp/SampleApp.gyp
+++ b/gyp/SampleApp.gyp
@@ -23,16 +23,6 @@
         'gmslides.gypi',
       ],
       'sources': [
-        '../src/utils/debugger/SkDrawCommand.h',
-        '../src/utils/debugger/SkDrawCommand.cpp',
-        '../src/utils/debugger/SkDebugCanvas.h',
-        '../src/utils/debugger/SkDebugCanvas.cpp',
-        '../src/utils/debugger/SkObjectParser.h',
-        '../src/utils/debugger/SkObjectParser.cpp',
-
-        '../gm/gm.cpp',
-        '../gm/gm.h',
-
         '../samplecode/GMSampleView.h',
         '../samplecode/ClockFaceView.cpp',
         '../samplecode/OverView.cpp',
diff --git a/gyp/bench.gyp b/gyp/bench.gyp
index d404000..c408d7c 100644
--- a/gyp/bench.gyp
+++ b/gyp/bench.gyp
@@ -97,6 +97,9 @@
         '../bench/SkBenchLogger.h',
         '../bench/SkBenchmark.cpp',
         '../bench/SkBenchmark.h',
+        '../bench/SkGMBench.cpp',
+        '../bench/SkGMBench.h',
+
         '../bench/benchmain.cpp',
       ],
       'conditions': [
@@ -111,6 +114,9 @@
           },
         ],
       ],
+      'includes': [
+        'gmslides.gypi',
+      ],
     },
     {
       'target_name' : 'bench_timer',
diff --git a/gyp/gm.gyp b/gyp/gm.gyp
index 971fce5..3533aa5 100644
--- a/gyp/gm.gyp
+++ b/gyp/gm.gyp
@@ -30,29 +30,19 @@
       'include_dirs' : [
         '../src/core',
         '../src/images',
-        '../src/lazy',
         '../src/effects',
         '../src/pipe/utils/',
         '../src/utils/',
-        '../src/utils/debugger',
       ],
       'includes': [
         'gmslides.gypi',
       ],
       'sources': [
-        '../gm/gm.cpp',
         '../gm/gmmain.cpp',
         '../gm/system_preferences_default.cpp',
 
         '../src/pipe/utils/SamplePipeControllers.h',
         '../src/pipe/utils/SamplePipeControllers.cpp',
-
-        '../src/utils/debugger/SkDrawCommand.h',
-        '../src/utils/debugger/SkDrawCommand.cpp',
-        '../src/utils/debugger/SkDebugCanvas.h',
-        '../src/utils/debugger/SkDebugCanvas.cpp',
-        '../src/utils/debugger/SkObjectParser.h',
-        '../src/utils/debugger/SkObjectParser.cpp',
       ],
       'dependencies': [
         'skia_lib.gyp:skia_lib',
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index 2ba0140..c6c11e3 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -1,6 +1,17 @@
 # include this gypi to include all the golden master slides.
 {
+  'include_dirs': [
+    '../gm',
+    # include dirs needed by particular GMs
+    '../src/utils/debugger',
+    '../src/images',
+    '../src/lazy',
+  ],
   'sources': [
+    # base class for GMs
+    '../gm/gm.cpp',
+    '../gm/gm.h',
+
     '../gm/aaclip.cpp',
     '../gm/aarectmodes.cpp',
     '../gm/alphagradients.cpp',
@@ -156,5 +167,14 @@
     '../gm/xfermodes.cpp',
     '../gm/xfermodes2.cpp',
     '../gm/xfermodes3.cpp',
+
+    # Files needed by particular GMs
+    '../src/utils/debugger/SkDrawCommand.h',
+    '../src/utils/debugger/SkDrawCommand.cpp',
+    '../src/utils/debugger/SkDebugCanvas.h',
+    '../src/utils/debugger/SkDebugCanvas.cpp',
+    '../src/utils/debugger/SkObjectParser.h',
+    '../src/utils/debugger/SkObjectParser.cpp',
+
   ],
 }