Make GM able to run MSAA modes and multiple GPU configs in a single run.

Review URL: http://codereview.appspot.com/6061051/



git-svn-id: http://skia.googlecode.com/svn/trunk@3734 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 7d47bbe..3855f2f 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -7,9 +7,8 @@
 
 #include "gm.h"
 #include "system_preferences.h"
-#include "GrContext.h"
+#include "GrContextFactory.h"
 #include "GrRenderTarget.h"
-
 #include "SkColorPriv.h"
 #include "SkData.h"
 #include "SkDeferredCanvas.h"
@@ -19,14 +18,6 @@
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
-#include "gl/SkNativeGLContext.h"
-#if SK_MESA
-#include "gl/SkMesaGLContext.h"
-#endif
-#if SK_ANGLE
-#include "gl/SkANGLEGLContext.h"
-#endif
-#include "gl/SkDebugGLContext.h"
 #include "SkPicture.h"
 #include "SkStream.h"
 
@@ -233,10 +224,22 @@
   kXPS_Backend,
 };
 
+enum ConfigFlags {
+    kNone_ConfigFlag  = 0x0,
+    /* Write GM images if a write path is provided. */
+    kWrite_ConfigFlag = 0x1,
+    /* Read comparison GM images if a read path is provided. */
+    kRead_ConfigFlag  = 0x2,
+    kRW_ConfigFlag    = (kWrite_ConfigFlag | kRead_ConfigFlag),
+};
+
 struct ConfigData {
-    SkBitmap::Config    fConfig;
-    Backend             fBackend;
-    const char*         fName;
+    SkBitmap::Config                fConfig;
+    Backend                         fBackend;
+    GrContextFactory::GLContextType fGLContextType; // GPU backend only
+    int                             fSampleCnt;     // GPU backend only
+    ConfigFlags                     fFlags;
+    const char*                     fName;
 };
 
 /// Returns true if processing should continue, false to skip the
@@ -464,14 +467,11 @@
     SkString name = make_name(gm->shortName(), gRec.fName);
     ErrorBitfield retval = ERROR_NONE;
 
-    if (readPath && (
-                   gRec.fBackend == kRaster_Backend ||
-                   gRec.fBackend == kGPU_Backend ||
-                   (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF))) {
+    if (readPath && (gRec.fFlags & kRead_ConfigFlag)) {
         retval |= compare_to_reference_image(readPath, name, bitmap,
                                              diffPath, renderModeDescriptor);
     }
-    if (writePath) {
+    if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) {
         retval |= write_reference_image(gRec, writePath, renderModeDescriptor,
                                         name, bitmap, pdf);
     }
@@ -615,14 +615,7 @@
         "%s [-w writePath] [-r readPath] [-d diffPath] [-i resourcePath]\n"
         "    [--noreplay] [--serialize] [--forceBWtext] [--nopdf] \n"
         "    [--nodeferred] [--match substring] [--notexturecache]\n"
-        "    "
-#if SK_MESA
-        "[--mesagl]"
-#endif
-#if SK_ANGLE
-        " [--angle]"
-#endif
-        " [--debuggl]\n\n", argv0);
+        , argv0);
     SkDebugf("    writePath: directory to write rendered images in.\n");
     SkDebugf(
 "    readPath: directory to read reference images from;\n"
@@ -636,28 +629,40 @@
     SkDebugf("    --nopdf: skip the pdf rendering test pass.\n");
     SkDebugf("    --nodeferred: skip the deferred rendering test pass.\n");
     SkDebugf("    --match foo: will only run tests that substring match foo.\n");
-#if SK_MESA
-    SkDebugf("    --mesagl: will run using the osmesa sw gl rasterizer.\n");
-#endif
-#if SK_ANGLE
-    SkDebugf("    --angle: use ANGLE backend on Windows.\n");
-#endif
-    SkDebugf("    --debuggl: will run using the debugging gl utility.\n");
     SkDebugf("    --notexturecache: disable the gpu texture cache.\n");
 }
 
+static const GrContextFactory::GLContextType kDontCare_GLContextType =
+    GrContextFactory::kNative_GLContextType;
+
+// If the platform does not support writing PNGs of PDFs then there will be no
+// comparison images to read. However, we can always write the .pdf files
+static const ConfigFlags kPDFConfigFlags = CAN_IMAGE_PDF ? kRW_ConfigFlag :
+                                                           kWrite_ConfigFlag;
+
 static const ConfigData gRec[] = {
-    { SkBitmap::kARGB_8888_Config, kRaster_Backend, "8888" },
-    { SkBitmap::kARGB_4444_Config, kRaster_Backend, "4444" },
-    { SkBitmap::kRGB_565_Config,   kRaster_Backend, "565" },
+    { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextType,                  0, kRW_ConfigFlag,    "8888" },
+    { SkBitmap::kARGB_4444_Config, kRaster_Backend, kDontCare_GLContextType,                  0, kRW_ConfigFlag,    "4444" },
+    { SkBitmap::kRGB_565_Config,   kRaster_Backend, kDontCare_GLContextType,                  0, kRW_ConfigFlag,    "565" },
 #ifdef SK_SCALAR_IS_FLOAT
-    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    "gpu" },
-#endif
-#ifdef SK_SUPPORT_PDF
-    { SkBitmap::kARGB_8888_Config, kPDF_Backend,    "pdf" },
+    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    GrContextFactory::kNative_GLContextType,  0, kRW_ConfigFlag,    "gpu" },
+    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    GrContextFactory::kNative_GLContextType, 16, kRW_ConfigFlag,    "msaa16" },
+    /* The debug context does not generate images */
+    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    GrContextFactory::kDebug_GLContextType,   0, kNone_ConfigFlag,  "debug" },
+  #ifdef SK_ANGLE
+    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    GrContextFactory::kANGLE_GLContextType,   0, kRW_ConfigFlag,    "angle" },
+    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    GrContextFactory::kANGLE_GLContextType,  16, kRW_ConfigFlag,    "anglemsaa16" },
+  #endif
+  #ifdef SK_MESA
+    { SkBitmap::kARGB_8888_Config, kGPU_Backend,    GrContextFactory::kMESA_GLContextType,    0, kRW_ConfigFlag,    "mesa" },
+  #endif
 #endif
 #ifdef SK_SUPPORT_XPS
-    { SkBitmap::kARGB_8888_Config, kXPS_Backend,    "xps" },
+    /* At present we have no way of comparing XPS files (either natively or by converting to PNG). */
+    { SkBitmap::kARGB_8888_Config, kXPS_Backend,    kDontCare_GLContextType,                  0, kWrite_ConfigFlag, "xps" },
+#endif
+#ifdef SK_SUPPORT_PDF
+    { SkBitmap::kARGB_8888_Config, kPDF_Backend,    kDontCare_GLContextType,                  0, kPDFConfigFlags,   "pdf" },
 #endif
 };
 
@@ -676,10 +681,39 @@
 }
 
 namespace skiagm {
-static GrContext* gGrContext;
-GrContext* GetGr() {
-    return gGrContext;
+SkAutoTUnref<GrContext> gGrContext;
+/**
+ * Sets the global GrContext, accessible by indivual GMs
+ */
+void SetGr(GrContext* grContext) {
+    SkSafeRef(grContext);
+    gGrContext.reset(grContext);
 }
+
+/**
+ * Gets the global GrContext, can be called by GM tests.
+ */
+GrContext* GetGr() {
+    return gGrContext.get();
+}
+
+/**
+ * Sets the global GrContext and then resets it to its previous value at
+ * destruction.
+ */
+class AutoResetGr : SkNoncopyable {
+public:
+    AutoResetGr() : fOld(NULL) {}
+    void set(GrContext* context) {
+        SkASSERT(NULL == fOld);
+        fOld = GetGr();
+        SkSafeRef(fOld);
+        SetGr(context);
+    }
+    ~AutoResetGr() { SetGr(fOld); SkSafeUnref(fOld); }
+private:
+    GrContext* fOld;
+};
 }
 
 int main(int argc, char * const argv[]) {
@@ -699,12 +733,6 @@
     bool doPDF = true;
     bool doReplay = true;
     bool doSerialize = false;
-#if SK_MESA
-    bool useMesa = false;
-#endif
-#if SK_ANGLE
-    bool useAngle = false;
-#endif
     bool useDebugGL = false;
     bool doDeferred = true;
     bool disableTextureCache = false;
@@ -748,16 +776,6 @@
                 // just record the ptr, no need for a deep copy
                 *fMatches.append() = *argv;
             }
-#if SK_MESA
-        } else if (strcmp(*argv, "--mesagl") == 0) {
-            useMesa = true;
-#endif
-#if SK_ANGLE
-        } else if (strcmp(*argv, "--angle") == 0) {
-            useAngle = true;
-#endif
-        } else if (strcmp(*argv, "--debuggl") == 0) {
-            useDebugGL = true;
         } else if (strcmp(*argv, "--notexturecache") == 0) {
             disableTextureCache = true;
         } else {
@@ -772,49 +790,7 @@
 
     GM::SetResourcePath(resourcePath);
 
-    int maxW = -1;
-    int maxH = -1;
-    Iter iter;
-    GM* gm;
-    while ((gm = iter.next()) != NULL) {
-        SkISize size = gm->getISize();
-        maxW = SkMax32(size.width(), maxW);
-        maxH = SkMax32(size.height(), maxH);
-        // This fixes a memory leak, but we are churning gms; we could
-        // instead cache them if we have constructors with side-effects.
-        SkDELETE(gm);
-    }
-    // setup a GL context for drawing offscreen
-    SkAutoTUnref<SkGLContext> glContext;
-#if SK_MESA
-    if (useMesa) {
-        glContext.reset(new SkMesaGLContext());
-    } else
-#endif
-#if SK_ANGLE
-    if (useAngle) {
-        glContext.reset(new SkANGLEGLContext());
-    } else
-#endif
-    if (useDebugGL) {
-        glContext.reset(new SkDebugGLContext());
-    } else {
-        glContext.reset(new SkNativeGLContext());
-    }
-
-    GrPlatformRenderTargetDesc rtDesc;
-    if (glContext.get()->init(maxW, maxH)) {
-        GrPlatform3DContext ctx =
-            reinterpret_cast<GrPlatform3DContext>(glContext.get()->gl());
-        gGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx);
-        if (NULL != gGrContext) {
-            rtDesc.fConfig = kSkia8888_PM_GrPixelConfig;
-            rtDesc.fStencilBits = 8;
-            rtDesc.fRenderTargetHandle = glContext.get()->getFBOID();
-        }
-    } else {
-        fprintf(stderr, "could not create GL context.\n");
-    }
+    GrContextFactory grFactory;
 
     if (readPath) {
         fprintf(stderr, "reading from %s\n", readPath);
@@ -837,7 +813,8 @@
         skiagm::GetGr()->setTextureCacheLimits(0, 0);
     }
 
-    iter.reset();
+    Iter iter;
+    GM* gm;
     while ((gm = iter.next()) != NULL) {
         const char* shortName = gm->shortName();
         if (skip_name(fMatches, shortName)) {
@@ -850,20 +827,33 @@
                  size.width(), size.height());
         SkBitmap forwardRenderedBitmap;
 
-        // Above we created an fbo for the context at maxW x maxH size.
-        // Here we lie about the size of the rt. We claim it is the size
-        // desired by the test. The reason is that rasterization may change
-        // slightly when the viewport dimensions change. Previously, whenever
-        // a new test was checked in that bumped maxW or maxH several images
-        // would slightly change.
-        rtDesc.fWidth = size.width();
-        rtDesc.fHeight = size.height();
-        SkAutoTUnref<GrRenderTarget> rt;
-        if (gGrContext) {
-            rt.reset(gGrContext->createPlatformRenderTarget(rtDesc));
-        }
-
         for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) {
+            SkAutoTUnref<GrRenderTarget> rt;
+            AutoResetGr autogr;
+            if (kGPU_Backend == gRec[i].fBackend) {
+                GrContext* gr = grFactory.get(gRec[i].fGLContextType);
+                if (!gr) {
+                    continue;
+                }
+
+                // create a render target to back the device
+                GrTextureDesc desc;
+                desc.fConfig = kSkia8888_PM_GrPixelConfig;
+                desc.fFlags = kRenderTarget_GrTextureFlagBit;
+                desc.fWidth = gm->getISize().width();
+                desc.fHeight = gm->getISize().height();
+                desc.fSampleCnt = gRec[i].fSampleCnt;
+                GrTexture* tex = gr->createUncachedTexture(desc, NULL, 0);
+                if (!tex) {
+                    return false;
+                }
+                rt.reset(tex->asRenderTarget());
+                rt.get()->ref();
+                tex->unref();
+
+                autogr.set(gr);
+            }
+
             // Skip any tests that we don't even need to try.
             uint32_t gmFlags = gm->getFlags();
             if ((kPDF_Backend == gRec[i].fBackend) &&
@@ -886,7 +876,7 @@
             if (ERROR_NONE == testErrors) {
                 testErrors |= test_drawing(gm, gRec[i],
                                            writePath, readPath, diffPath,
-                                           gGrContext,
+                                           GetGr(),
                                            rt.get(), &forwardRenderedBitmap);
             }
 
@@ -895,7 +885,7 @@
                  kRaster_Backend == gRec[i].fBackend)) {
                 testErrors |= test_deferred_drawing(gm, gRec[i],
                                                     forwardRenderedBitmap,
-                                                    diffPath, gGrContext, rt.get());
+                                                    diffPath, GetGr(), rt.get());
             }
 
             if ((ERROR_NONE == testErrors) && doReplay &&
@@ -931,8 +921,5 @@
     printf("Ran %d tests: %d passed, %d failed, %d missing reference images\n",
            testsRun, testsPassed, testsFailed, testsMissingReferenceImages);
 
-    SkDELETE(skiagm::gGrContext);
-    skiagm::gGrContext = NULL;
-
     return (0 == testsFailed) ? 0 : -1;
 }