Add config options to run different GPU APIs to dm and nanobench
authorkkinnunen <kkinnunen@nvidia.com>
Fri, 18 Dec 2015 11:27:32 +0000 (03:27 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 18 Dec 2015 11:27:32 +0000 (03:27 -0800)
Add extended config specification form that can be used to run different
gpu backend with different APIs.

The configs can be specified with the form:
gpu(api=string,dit=bool,nvpr=bool,samples=int)

This replaces and removes the --gpuAPI flag.

All existing configs should still work.

Adds following documentation:

out/Debug/dm --help config

Flags:
    --config: type: string default: 565 8888 gpu nonrendering
        Options: 565 8888 debug gpu gpudebug gpudft gpunull msaa16 msaa4
        nonrendering null nullgpu nvprmsaa16 nvprmsaa4 pdf pdf_poppler skp svg
        xps or use extended form 'backend(option=value,...)'.

        Extended form: 'backend(option=value,...)'

        Possible backends and options:

        gpu(api=string,dit=bool,nvpr=bool,samples=int) GPU backend
         api type: string default: native.
             Select graphics API to use with gpu backend.
             Options:
         native Use platform default OpenGL or OpenGL ES backend.
         gl     Use OpenGL.
         gles   Use OpenGL ES.
         debug  Use debug OpenGL.
         null   Use null OpenGL.
         dit type: bool default: false.
             Use device independent text.
         nvpr type: bool default: false.
             Use NV_path_rendering OpenGL and OpenGL ES extension.
         samples type: int default: 0.
             Use multisampling with N samples.

        Predefined configs:

         gpu       = gpu()
         msaa4     = gpu(samples=4)
         msaa16    = gpu(samples=16)
         nvprmsaa4 = gpu(nvpr=true,samples=4)
         nvprmsaa16 = gpu(nvpr=true,samples=16)
         gpudft     = gpu(dit=true)
         gpudebug   = gpu(api=debug)
         gpunull    = gpu(api=null)
         debug      = gpu(api=debug)
         nullgpu    = gpu(api=null)

BUG=skia:2992

Committed: https://skia.googlesource.com/skia/+/e13ca329fca4c28cf4e078561f591ab27b743d23
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1490113005

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

27 files changed:
bench/nanobench.cpp
dm/DM.cpp
dm/DMGpuSupport.h
dm/DMSrcSink.cpp
dm/DMSrcSink.h
gyp/flags.gyp
include/core/SkString.h
include/gpu/gl/SkNullGLContext.h
include/gpu/gl/angle/SkANGLEGLContext.h
include/gpu/gl/command_buffer/SkCommandBufferGLContext.h
src/core/SkString.cpp
src/gpu/GrContextFactory.cpp
src/gpu/GrContextFactory.h
src/gpu/gl/SkNullGLContext.cpp
src/gpu/gl/angle/SkANGLEGLContext.cpp
src/gpu/gl/debug/SkDebugGLContext.h
src/gpu/gl/mesa/SkMesaGLContext.h
tests/GLProgramsTest.cpp
tests/GrContextFactoryTest.cpp
tests/StringTest.cpp
tests/TestConfigParsing.cpp [new file with mode: 0644]
tools/flags/SkCommandLineFlags.cpp
tools/flags/SkCommandLineFlags.h
tools/flags/SkCommonFlags.cpp
tools/flags/SkCommonFlags.h
tools/flags/SkCommonFlagsConfig.cpp [new file with mode: 0644]
tools/flags/SkCommonFlagsConfig.h [new file with mode: 0644]

index 11119be2e193b9900b84c7fb4c1981ea533c5388..638477ecf6fc8720af438cf07dde48b162fcb19f 100644 (file)
@@ -28,6 +28,7 @@
 #include "SkCanvas.h"
 #include "SkCodec.h"
 #include "SkCommonFlags.h"
+#include "SkCommonFlagsConfig.h"
 #include "SkData.h"
 #include "SkForceLinking.h"
 #include "SkGraphics.h"
@@ -168,11 +169,10 @@ struct GPUTarget : public Target {
                                                   0;
         SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
         this->surface.reset(SkSurface::NewRenderTarget(gGrFactory->get(this->config.ctxType,
-                                                                       kNone_GrGLStandard,
                                                                        this->config.ctxOptions),
                                                          SkSurface::kNo_Budgeted, info,
                                                          this->config.samples, &props));
-        this->gl = gGrFactory->getContextInfo(this->config.ctxType, kNone_GrGLStandard,
+        this->gl = gGrFactory->getContextInfo(this->config.ctxType,
                                               this->config.ctxOptions)->fGLContext;
         if (!this->surface.get()) {
             return false;
@@ -390,7 +390,7 @@ static bool is_gpu_config_allowed(const char* name, GrContextFactory::GLContextT
     if (!is_cpu_config_allowed(name)) {
         return false;
     }
-    if (const GrContext* ctx = gGrFactory->get(ctxType, kNone_GrGLStandard, ctxOptions)) {
+    if (const GrContext* ctx = gGrFactory->get(ctxType, ctxOptions)) {
         return sampleCnt <= ctx->caps()->maxSampleCount();
     }
     return false;
@@ -446,11 +446,13 @@ static void create_configs(SkTDArray<Config>* configs) {
         GPU_CONFIG(gpudft, kNative_GLContextType, kNone_GLContextOptions, 0, true)
         GPU_CONFIG(debug, kDebug_GLContextType, kNone_GLContextOptions, 0, false)
         GPU_CONFIG(nullgpu, kNull_GLContextType, kNone_GLContextOptions, 0, false)
-#ifdef SK_ANGLE
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
         GPU_CONFIG(angle, kANGLE_GLContextType, kNone_GLContextOptions, 0, false)
+#endif
         GPU_CONFIG(angle-gl, kANGLE_GL_GLContextType, kNone_GLContextOptions, 0, false)
 #endif
-#ifdef SK_COMMAND_BUFFER
+#if SK_COMMAND_BUFFER
         GPU_CONFIG(commandbuffer, kCommandBuffer_GLContextType, kNone_GLContextOptions, 0, false)
 #endif
 #if SK_MESA
@@ -1166,7 +1168,7 @@ int nanobench_main() {
 #if SK_SUPPORT_GPU
             if (FLAGS_gpuStats && Benchmark::kGPU_Backend == configs[i].backend) {
                 GrContext* context = gGrFactory->get(configs[i].ctxType,
-                                                     kNone_GrGLStandard, configs[i].ctxOptions);
+                                                     configs[i].ctxOptions);
                 context->printCacheStats();
                 context->printGpuStats();
             }
index c7e0934008f3b5a8b2d8dd982976d169b1c923e0..2351366fef21d7deaf2be60995dd6dd988aaa62d 100644 (file)
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -15,6 +15,7 @@
 #include "SkChecksum.h"
 #include "SkCodec.h"
 #include "SkCommonFlags.h"
+#include "SkCommonFlagsConfig.h"
 #include "SkFontMgr.h"
 #include "SkForceLinking.h"
 #include "SkGraphics.h"
@@ -199,7 +200,7 @@ struct TaggedSrc : public SkAutoTDelete<Src> {
 };
 
 struct TaggedSink : public SkAutoTDelete<Sink> {
-    const char* tag;
+    SkString tag;
 };
 
 static const bool kMemcpyOK = true;
@@ -541,19 +542,9 @@ static void gather_srcs() {
     }
 }
 
-#if SK_SUPPORT_GPU
-static GrGLStandard get_gpu_api() {
-    if (FLAGS_gpuAPI.contains("gl"))   { return kGL_GrGLStandard; }
-    if (FLAGS_gpuAPI.contains("gles")) { return kGLES_GrGLStandard; }
-    return kNone_GrGLStandard;
-}
-#endif
-
-static void push_sink(const char* tag, Sink* s) {
+static void push_sink(const SkCommandLineConfig& config, Sink* s) {
     SkAutoTDelete<Sink> sink(s);
-    if (!FLAGS_config.contains(tag)) {
-        return;
-    }
+
     // Try a simple Src as a canary.  If it fails, skip this sink.
     struct : public Src {
         Error draw(SkCanvas* c) const override {
@@ -569,13 +560,13 @@ static void push_sink(const char* tag, Sink* s) {
     SkString log;
     Error err = sink->draw(justOneRect, &bitmap, &stream, &log);
     if (err.isFatal()) {
-        SkDebugf("Could not run %s: %s\n", tag, err.c_str());
+        SkDebugf("Could not run %s: %s\n", config.getTag().c_str(), err.c_str());
         exit(1);
     }
 
     TaggedSink& ts = gSinks.push_back();
     ts.reset(sink.detach());
-    ts.tag = tag;
+    ts.tag = config.getTag();
 }
 
 static bool gpu_supported() {
@@ -585,45 +576,32 @@ static bool gpu_supported() {
     return false;
 #endif
 }
-static Sink* create_gpu_sink(const char* tag, GrContextFactory::GLContextType contextType,
-                             GrContextFactory::GLContextOptions contextOptions, int samples,
-                             bool diText, bool threaded) {
+
+static Sink* create_sink(const SkCommandLineConfig* config) {
 #if SK_SUPPORT_GPU
-    GrContextFactory testFactory;
-    const GrGLStandard api = get_gpu_api();
-    if (testFactory.get(contextType, api, contextOptions)) {
-        return new GPUSink(contextType, contextOptions, api, samples, diText, threaded);
-    }
-    SkDebugf("WARNING: can not create GPU context for config '%s'. GM tests will be skipped.\n", tag);
-#endif
-    return nullptr;
-}
-static Sink* create_sink(const char* tag) {
-#define GPU_SINK(t, ...) if (0 == strcmp(t, tag)) { return create_gpu_sink(tag, __VA_ARGS__); }
     if (gpu_supported()) {
-        typedef GrContextFactory Gr;
-        GPU_SINK("gpunull",       Gr::kNull_GLContextType,          Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-        GPU_SINK("gpudebug",      Gr::kDebug_GLContextType,         Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-        GPU_SINK("gpu",           Gr::kNative_GLContextType,        Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-        GPU_SINK("gpudft",        Gr::kNative_GLContextType,        Gr::kNone_GLContextOptions,        0,  true, FLAGS_gpu_threading);
-        GPU_SINK("msaa4",         Gr::kNative_GLContextType,        Gr::kNone_GLContextOptions,        4, false, FLAGS_gpu_threading);
-        GPU_SINK("msaa16",        Gr::kNative_GLContextType,        Gr::kNone_GLContextOptions,       16, false, FLAGS_gpu_threading);
-        GPU_SINK("nvprmsaa4",     Gr::kNative_GLContextType,        Gr::kEnableNVPR_GLContextOptions,  4,  true, FLAGS_gpu_threading);
-        GPU_SINK("nvprmsaa16",    Gr::kNative_GLContextType,        Gr::kEnableNVPR_GLContextOptions, 16,  true, FLAGS_gpu_threading);
-#if SK_ANGLE
-        GPU_SINK("angle",         Gr::kANGLE_GLContextType,         Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-        GPU_SINK("angle-gl",      Gr::kANGLE_GL_GLContextType,      Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-#endif
-#if SK_COMMAND_BUFFER
-        GPU_SINK("commandbuffer", Gr::kCommandBuffer_GLContextType, Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-#endif
-#if SK_MESA
-        GPU_SINK("mesa",          Gr::kMESA_GLContextType,          Gr::kNone_GLContextOptions,        0, false, FLAGS_gpu_threading);
-#endif
+        if (const SkCommandLineConfigGpu* gpuConfig = config->asConfigGpu()) {
+            GrContextFactory::GLContextType contextType = gpuConfig->getContextType();
+            GrContextFactory::GLContextOptions contextOptions =
+                    GrContextFactory::kNone_GLContextOptions;
+            if (gpuConfig->getUseNVPR()) {
+                contextOptions = static_cast<GrContextFactory::GLContextOptions>(
+                    contextOptions | GrContextFactory::kEnableNVPR_GLContextOptions);
+            }
+            GrContextFactory testFactory;
+            if (!testFactory.get(contextType, contextOptions)) {
+                SkDebugf("WARNING: can not create GPU context for config '%s'. "
+                         "GM tests will be skipped.\n", gpuConfig->getTag().c_str());
+                return nullptr;
+            }
+            return new GPUSink(contextType, contextOptions, gpuConfig->getSamples(),
+                               gpuConfig->getUseDIText(), FLAGS_gpu_threading);
+        }
     }
-#undef GPU_SINK
+#endif
+
+#define SINK(t, sink, ...) if (config->getTag().equals(t)) { return new sink(__VA_ARGS__); }
 
-#define SINK(t, sink, ...) if (0 == strcmp(t, tag)) { return new sink(__VA_ARGS__); }
 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
     SINK("hwui",           HWUISink);
 #endif
@@ -642,8 +620,8 @@ static Sink* create_sink(const char* tag) {
     return nullptr;
 }
 
-static Sink* create_via(const char* tag, Sink* wrapped) {
-#define VIA(t, via, ...) if (0 == strcmp(t, tag)) { return new via(__VA_ARGS__); }
+static Sink* create_via(const SkString& tag, Sink* wrapped) {
+#define VIA(t, via, ...) if (tag.equals(t)) { return new via(__VA_ARGS__); }
     VIA("twice",     ViaTwice,             wrapped);
     VIA("pipe",      ViaPipe,              wrapped);
     VIA("serialize", ViaSerialization,     wrapped);
@@ -674,17 +652,24 @@ static Sink* create_via(const char* tag, Sink* wrapped) {
 }
 
 static void gather_sinks() {
-    for (int i = 0; i < FLAGS_config.count(); i++) {
-        const char* config = FLAGS_config[i];
-        SkTArray<SkString> parts;
-        SkStrSplit(config, "-", &parts);
-
-        Sink* sink = nullptr;
-        for (int i = parts.count(); i-- > 0;) {
-            const char* part = parts[i].c_str();
-            Sink* next = (sink == nullptr) ? create_sink(part) : create_via(part, sink);
+    SkCommandLineConfigArray configs;
+    ParseConfigs(FLAGS_config, &configs);
+    for (int i = 0; i < configs.count(); i++) {
+        const SkCommandLineConfig& config = *configs[i];
+        Sink* sink = create_sink(&config);
+        if (sink == nullptr) {
+            SkDebugf("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
+                     config.getTag().c_str());
+            continue;
+        }
+
+        const SkTArray<SkString>& parts = config.getViaParts();
+        for (int j = parts.count(); j-- > 0;) {
+            const SkString& part = parts[j];
+            Sink* next = create_via(part, sink);
             if (next == nullptr) {
-                SkDebugf("Skipping %s: Don't understand '%s'.\n", config, part);
+                SkDebugf("Skipping config %s: Don't understand '%s'.\n", config.getTag().c_str(),
+                         part.c_str());
                 delete sink;
                 sink = nullptr;
                 break;
@@ -806,7 +791,7 @@ struct Task {
         //   - this Src / Sink combination is on the blacklist;
         //   - it's a dry run.
         SkString note(task->src->veto(task->sink->flags()) ? " (veto)" : "");
-        SkString whyBlacklisted = is_blacklisted(task->sink.tag, task->src.tag.c_str(),
+        SkString whyBlacklisted = is_blacklisted(task->sink.tag.c_str(), task->src.tag.c_str(),
                                                  task->src.options.c_str(), name.c_str());
         if (!whyBlacklisted.isEmpty()) {
             note.appendf(" (--blacklist %s)", whyBlacklisted.c_str());
@@ -818,15 +803,15 @@ struct Task {
             SkBitmap bitmap;
             SkDynamicMemoryWStream stream;
             if (FLAGS_pre_log) {
-                SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag);
+                SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag.c_str());
             }
-            start(task->sink.tag, task->src.tag, task->src.options, name.c_str());
+            start(task->sink.tag.c_str(), task->src.tag, task->src.options, name.c_str());
             Error err = task->sink->draw(*task->src, &bitmap, &stream, &log);
             if (!err.isEmpty()) {
                 auto elapsed = now_ms() - timerStart;
                 if (err.isFatal()) {
                     fail(SkStringPrintf("%s %s %s %s: %s",
-                                        task->sink.tag,
+                                        task->sink.tag.c_str(),
                                         task->src.tag.c_str(),
                                         task->src.options.c_str(),
                                         name.c_str(),
@@ -834,7 +819,7 @@ struct Task {
                 } else {
                     note.appendf(" (skipped: %s)", err.c_str());
                 }
-                done(elapsed, task->sink.tag, task->src.tag, task->src.options,
+                done(elapsed, task->sink.tag.c_str(), task->src.tag, task->src.options,
                      name, note, log);
                 return;
             }
@@ -867,11 +852,11 @@ struct Task {
             }
 
             if (!FLAGS_readPath.isEmpty() &&
-                !gGold.contains(Gold(task->sink.tag, task->src.tag.c_str(),
+                !gGold.contains(Gold(task->sink.tag.c_str(), task->src.tag.c_str(),
                                      task->src.options.c_str(), name, md5))) {
                 fail(SkStringPrintf("%s not found for %s %s %s %s in %s",
                                     md5.c_str(),
-                                    task->sink.tag,
+                                    task->sink.tag.c_str(),
                                     task->src.tag.c_str(),
                                     task->src.options.c_str(),
                                     name.c_str(),
@@ -888,7 +873,7 @@ struct Task {
                 }
             }
         }
-        done(now_ms()-timerStart, task->sink.tag, task->src.tag.c_str(), task->src.options.c_str(),
+        done(now_ms()-timerStart, task->sink.tag.c_str(), task->src.tag.c_str(), task->src.options.c_str(),
              name, note, log);
     }
 
@@ -899,7 +884,7 @@ struct Task {
                             const SkBitmap* bitmap) {
         JsonWriter::BitmapResult result;
         result.name          = task.src->name();
-        result.config        = task.sink.tag;
+        result.config        = task.sink.tag.c_str();
         result.sourceType    = task.src.tag;
         result.sourceOptions = task.src.options;
         result.ext           = ext;
@@ -927,7 +912,7 @@ struct Task {
                 return;  // Content-addressed.  If it exists already, we're done.
             }
         } else {
-            path = SkOSPath::Join(dir, task.sink.tag);
+            path = SkOSPath::Join(dir, task.sink.tag.c_str());
             sk_mkdir(path.c_str());
             path = SkOSPath::Join(path.c_str(), task.src.tag.c_str());
             sk_mkdir(path.c_str());
@@ -1179,28 +1164,48 @@ template<typename T>
 void RunWithGPUTestContexts(T test, GPUTestContexts testContexts, Reporter* reporter,
                             GrContextFactory* factory) {
 #if SK_SUPPORT_GPU
-    const GrGLStandard api = get_gpu_api();
-    for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
-        GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
+    // Iterate over context types, except use "native" instead of explicitly trying OpenGL and
+    // OpenGL ES. Do not use GLES on desktop, since tests do not account for not fixing
+    // http://skbug.com/2809
+    GrContextFactory::GLContextType contextTypes[] = {
+        GrContextFactory::kNative_GLContextType,
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+        GrContextFactory::kANGLE_GLContextType,
+#endif
+        GrContextFactory::kANGLE_GL_GLContextType,
+#endif
+#if SK_COMMAND_BUFFER
+        GrContextFactory::kCommandBuffer_GLContextType,
+#endif
+#if SK_MESA
+        GrContextFactory::kMESA_GLContextType,
+#endif
+        GrContextFactory::kNull_GLContextType,
+        GrContextFactory::kDebug_GLContextType,
+    };
+    static_assert(SK_ARRAY_COUNT(contextTypes) == GrContextFactory::kGLContextTypeCnt - 2,
+                  "Skipping unexpected GLContextType for GPU tests");
+
+    for (auto& contextType : contextTypes) {
         int contextSelector = kNone_GPUTestContexts;
-        if (GrContextFactory::IsRenderingGLContext(glCtxType)) {
+        if (GrContextFactory::IsRenderingGLContext(contextType)) {
             contextSelector |= kAllRendering_GPUTestContexts;
-        } else if (glCtxType == GrContextFactory::kNative_GLContextType) {
+        } else if (contextType == GrContextFactory::kNative_GLContextType) {
             contextSelector |= kNative_GPUTestContexts;
-        } else if (glCtxType == GrContextFactory::kNull_GLContextType) {
+        } else if (contextType == GrContextFactory::kNull_GLContextType) {
             contextSelector |= kNull_GPUTestContexts;
-        } else if (glCtxType == GrContextFactory::kDebug_GLContextType) {
+        } else if (contextType == GrContextFactory::kDebug_GLContextType) {
             contextSelector |= kDebug_GPUTestContexts;
         }
         if ((testContexts & contextSelector) == 0) {
             continue;
         }
-        if (GrContextFactory::ContextInfo* context = factory->getContextInfo(glCtxType, api)) {
+        if (GrContextFactory::ContextInfo* context = factory->getContextInfo(contextType)) {
             call_test(test, reporter, context);
         }
         if (GrContextFactory::ContextInfo* context =
-            factory->getContextInfo(glCtxType, api,
-                                    GrContextFactory::kEnableNVPR_GLContextOptions)) {
+            factory->getContextInfo(contextType, GrContextFactory::kEnableNVPR_GLContextOptions)) {
             call_test(test, reporter, context);
         }
     }
index 627dc4fda321694bb2cdf68a15825fb1fa4e1b95..2cfdbdcc2c178d86a9d4cc301c5ca3e92770d587 100644 (file)
@@ -31,14 +31,13 @@ static const bool kGPUDisabled = false;
 static inline SkSurface* NewGpuSurface(GrContextFactory* grFactory,
                                        GrContextFactory::GLContextType type,
                                        GrContextFactory::GLContextOptions options,
-                                       GrGLStandard gpuAPI,
                                        SkImageInfo info,
                                        int samples,
                                        bool useDIText) {
     uint32_t flags = useDIText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0;
     SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
-    return SkSurface::NewRenderTarget(grFactory->get(type, gpuAPI, options),
-                                      SkSurface::kNo_Budgeted, info, samples, &props);
+    return SkSurface::NewRenderTarget(grFactory->get(type, options), SkSurface::kNo_Budgeted,
+                                      info, samples, &props);
 }
 
 }  // namespace DM
@@ -92,7 +91,6 @@ static const bool kGPUDisabled = true;
 static inline SkSurface* NewGpuSurface(GrContextFactory*,
                                        GrContextFactory::GLContextType,
                                        GrContextFactory::GLContextOptions,
-                                       GrGLStandard,
                                        SkImageInfo,
                                        int,
                                        bool) {
index e27628ad043aeedc9676dfd1a00187c843ad2fa8..5bc5e5a30d6494f44892ee5e53182ad6a9d18f16 100644 (file)
@@ -790,13 +790,11 @@ DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?");
 
 GPUSink::GPUSink(GrContextFactory::GLContextType ct,
                  GrContextFactory::GLContextOptions options,
-                 GrGLStandard gpuAPI,
                  int samples,
                  bool diText,
                  bool threaded)
     : fContextType(ct)
     , fContextOptions(options)
-    , fGpuAPI(gpuAPI)
     , fSampleCount(samples)
     , fUseDIText(diText)
     , fThreaded(threaded) {}
@@ -826,8 +824,7 @@ Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log) co
     const SkImageInfo info =
         SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType);
     SkAutoTUnref<SkSurface> surface(
-            NewGpuSurface(&factory, fContextType, fContextOptions, fGpuAPI, info, fSampleCount,
-                          fUseDIText));
+            NewGpuSurface(&factory, fContextType, fContextOptions, info, fSampleCount, fUseDIText));
     if (!surface) {
         return "Could not create a surface.";
     }
index 6b644ecdf36fd6c543d0c62c38ad34ad1b1e0b53..5e053b1155cfd57106bbc96e665bb53c8d3d720a 100644 (file)
@@ -215,7 +215,7 @@ public:
 class GPUSink : public Sink {
 public:
     GPUSink(GrContextFactory::GLContextType, GrContextFactory::GLContextOptions,
-            GrGLStandard, int samples, bool diText, bool threaded);
+            int samples, bool diText, bool threaded);
 
     Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
     int enclave() const override;
@@ -224,7 +224,6 @@ public:
 private:
     GrContextFactory::GLContextType    fContextType;
     GrContextFactory::GLContextOptions fContextOptions;
-    GrGLStandard                       fGpuAPI;
     int                                fSampleCount;
     bool                               fUseDIText;
     bool                               fThreaded;
index 0fd52b375b18c9c5e69bfcd88c5cf4a0ef1ec2b5..769a7bdb57721d1b35e212b7b41335c52006ae38 100644 (file)
     {
       'target_name': 'flags_common',
       'type': 'static_library',
+      'include_dirs': [
+          '../include/gpu',
+          '../src/gpu',
+      ],
       'sources': [
         '../tools/flags/SkCommonFlags.cpp',
         '../tools/flags/SkCommonFlags.h',
+        '../tools/flags/SkCommonFlagsConfig.cpp',
+        '../tools/flags/SkCommonFlagsConfig.h',
       ],
       'dependencies': [
         'skia_lib.gyp:skia_lib',
@@ -39,6 +45,8 @@
       ],
       'direct_dependent_settings': {
         'include_dirs': [
+          '../include/gpu',
+          '../src/gpu',
           '../tools/flags',
         ],
       }
index 9229d808a63d00ab79e758d249f5cd08952daf41..93514f2659febb67a6588cdc214595f278c825a4 100644 (file)
@@ -267,7 +267,22 @@ template <> inline void SkTSwap(SkString& a, SkString& b) {
     a.swap(b);
 }
 
+enum SkStrSplitMode {
+    // Strictly return all results. If the input is ",," and the separator is ',' this will return
+    // an array of three empty strings.
+    kStrict_SkStrSplitMode,
+
+    // Only nonempty results will be added to the results. Multiple separators will be
+    // coalesced. Separators at the beginning and end of the input will be ignored.  If the input is
+    // ",," and the separator is ',', this will return an empty vector.
+    kCoalesce_SkStrSplitMode
+};
+
 // Split str on any characters in delimiters into out.  (Think, strtok with a sane API.)
-void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out);
+void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
+                SkTArray<SkString>* out);
+inline void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
+    SkStrSplit(str, delimiters, kCoalesce_SkStrSplitMode, out);
+}
 
 #endif
index 1f634382641ec02dd336304f754a80c1ac78b5e2..9e799a9fea4d9d7b9b832026f4c664aee7a797ec 100644 (file)
@@ -14,7 +14,12 @@ class SK_API SkNullGLContext : public SkGLContext {
 public:
     ~SkNullGLContext() override;
 
-    static SkNullGLContext* Create(GrGLStandard);
+    static SkNullGLContext* Create();
+    // FIXME: remove once Chromium has been updated.
+    static SkNullGLContext* Create(GrGLStandard forcedAPI) {
+        SkASSERT(forcedAPI == kNone_GrGLStandard);
+        (void)forcedAPI;        return Create();
+    }
 
     class ContextState;
 
index 7858fff9649de75f4296936760bab8a5a4c47dc0..ea5e877ca27e8b3bae4565bcd38e111e3f2cc9f3 100644 (file)
 class SkANGLEGLContext : public SkGLContext {
 public:
     ~SkANGLEGLContext() override;
-
-    static SkANGLEGLContext* Create(GrGLStandard forcedGpuAPI, bool useGLBackend) {
-        if (kGL_GrGLStandard == forcedGpuAPI) {
+#ifdef SK_BUILD_FOR_WIN
+    static SkANGLEGLContext* CreateDirectX() {
+        SkANGLEGLContext* ctx = new SkANGLEGLContext(false);
+        if (!ctx->isValid()) {
+            delete ctx;
             return NULL;
         }
-        SkANGLEGLContext* ctx = new SkANGLEGLContext(useGLBackend);
+        return ctx;
+    }
+#endif
+    static SkANGLEGLContext* CreateOpenGL() {
+        SkANGLEGLContext* ctx = new SkANGLEGLContext(true);
         if (!ctx->isValid()) {
             delete ctx;
             return NULL;
         }
         return ctx;
     }
+
     GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
     void destroyEGLImage(GrEGLImage) const override;
     GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
index 7fece3c83c1a43eb7fd4d85bcfa0e08ae4fa7e51..47f3fd967a3b665217864a8d24690452e20751bd 100644 (file)
@@ -16,10 +16,7 @@ class SkCommandBufferGLContext : public SkGLContext {
 public:
     ~SkCommandBufferGLContext() override;
 
-    static SkCommandBufferGLContext* Create(GrGLStandard forcedGpuAPI) {
-        if (kGL_GrGLStandard == forcedGpuAPI) {
-            return nullptr;
-        }
+    static SkCommandBufferGLContext* Create() {
         SkCommandBufferGLContext* ctx = new SkCommandBufferGLContext;
         if (!ctx->isValid()) {
             delete ctx;
index d93f662da3d8bc0a80ca96903752bbcc3977ba1e..b5655e0503be9574f93047dc54f9158b343c25fc 100644 (file)
@@ -624,16 +624,35 @@ SkString SkStringPrintf(const char* format, ...) {
     return formattedOutput;
 }
 
-void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
-    const char* end = str + strlen(str);
-    while (str != end) {
-        // Find a token.
-        const size_t len = strcspn(str, delimiters);
-        out->push_back().set(str, len);
-        str += len;
+void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
+                SkTArray<SkString>* out) {
+    if (splitMode == kCoalesce_SkStrSplitMode) {
         // Skip any delimiters.
         str += strspn(str, delimiters);
     }
+    if (!*str) {
+        return;
+    }
+
+    while (true) {
+        // Find a token.
+        const size_t len = strcspn(str, delimiters);
+        if (splitMode == kStrict_SkStrSplitMode || len > 0) {
+            out->push_back().set(str, len);
+            str += len;
+        }
+
+        if (!*str) {
+            return;
+        }
+        if (splitMode == kCoalesce_SkStrSplitMode) {
+            // Skip any delimiters.
+            str += strspn(str, delimiters);
+        } else {
+            // Skip one delimiter.
+            str += 1;
+        }
+    }
 }
 
 #undef VSNPRINTF
index 15af8162b1e90bdbf0fa71d5da6c3ce358703eda..4814e7870e8f0f16e118e824d526abea7122f0a7 100755 (executable)
 #include "GrCaps.h"
 
 GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType type,
-                                                                GrGLStandard forcedGpuAPI,
                                                                 GLContextOptions options) {
     for (int i = 0; i < fContexts.count(); ++i) {
         if (fContexts[i]->fType == type &&
-            fContexts[i]->fOptions == options &&
-            (forcedGpuAPI == kNone_GrGLStandard ||
-             forcedGpuAPI == fContexts[i]->fGLContext->gl()->fStandard)) {
+            fContexts[i]->fOptions == options) {
             fContexts[i]->fGLContext->makeCurrent();
             return fContexts[i];
         }
@@ -39,31 +36,39 @@ GrContextFactory::ContextInfo* GrContextFactory::getContextInfo(GLContextType ty
     SkAutoTUnref<GrContext> grCtx;
     switch (type) {
         case kNative_GLContextType:
-            glCtx.reset(SkCreatePlatformGLContext(forcedGpuAPI));
+            glCtx.reset(SkCreatePlatformGLContext(kNone_GrGLStandard));
             break;
-#ifdef SK_ANGLE
+        case kGL_GLContextType:
+            glCtx.reset(SkCreatePlatformGLContext(kGL_GrGLStandard));
+            break;
+        case kGLES_GLContextType:
+            glCtx.reset(SkCreatePlatformGLContext(kGLES_GrGLStandard));
+            break;
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
         case kANGLE_GLContextType:
-            glCtx.reset(SkANGLEGLContext::Create(forcedGpuAPI, false));
+            glCtx.reset(SkANGLEGLContext::CreateDirectX());
             break;
+#endif
         case kANGLE_GL_GLContextType:
-            glCtx.reset(SkANGLEGLContext::Create(forcedGpuAPI, true));
+            glCtx.reset(SkANGLEGLContext::CreateOpenGL());
             break;
 #endif
-#ifdef SK_COMMAND_BUFFER
+#if SK_COMMAND_BUFFER
         case kCommandBuffer_GLContextType:
-            glCtx.reset(SkCommandBufferGLContext::Create(forcedGpuAPI));
+            glCtx.reset(SkCommandBufferGLContext::Create());
             break;
 #endif
-#ifdef SK_MESA
+#if SK_MESA
         case kMESA_GLContextType:
-            glCtx.reset(SkMesaGLContext::Create(forcedGpuAPI));
+            glCtx.reset(SkMesaGLContext::Create());
             break;
 #endif
         case kNull_GLContextType:
-            glCtx.reset(SkNullGLContext::Create(forcedGpuAPI));
+            glCtx.reset(SkNullGLContext::Create());
             break;
         case kDebug_GLContextType:
-            glCtx.reset(SkDebugGLContext::Create(forcedGpuAPI));
+            glCtx.reset(SkDebugGLContext::Create());
             break;
     }
     if (nullptr == glCtx.get()) {
index 50978138174a22c22b68f45727b1e32a96aab8bf..1df99d6ff1f88d1e516ac024c302eafcc25b9159 100644 (file)
 class GrContextFactory : SkNoncopyable {
 public:
     enum GLContextType {
-        kNative_GLContextType,
+        kNative_GLContextType,  //! OpenGL or OpenGL ES context.
+        kGL_GLContextType,      //! OpenGL context.
+        kGLES_GLContextType,    //! OpenGL ES context.
 #if SK_ANGLE
-        kANGLE_GLContextType,
-        kANGLE_GL_GLContextType,
+#ifdef SK_BUILD_FOR_WIN
+        kANGLE_GLContextType,    //! ANGLE on DirectX OpenGL ES context.
+#endif
+        kANGLE_GL_GLContextType, //! ANGLE on OpenGL OpenGL ES context.
 #endif
 #if SK_COMMAND_BUFFER
-        kCommandBuffer_GLContextType,
+        kCommandBuffer_GLContextType, //! Chromium command buffer OpenGL ES context.
 #endif
 #if SK_MESA
-        kMESA_GLContextType,
+        kMESA_GLContextType,  //! MESA OpenGL context
 #endif
-        kNull_GLContextType,
-        kDebug_GLContextType,
+        kNull_GLContextType,  //! Non-rendering OpenGL mock context.
+        kDebug_GLContextType, //! Non-rendering, state verifying OpenGL context.
         kLastGLContextType = kDebug_GLContextType
     };
 
@@ -65,11 +69,15 @@ public:
         switch (type) {
             case kNative_GLContextType:
                 return "native";
-            case kNull_GLContextType:
-                return "null";
+            case kGL_GLContextType:
+                return "gl";
+            case kGLES_GLContextType:
+                return "gles";
 #if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
             case kANGLE_GLContextType:
                 return "angle";
+#endif
             case kANGLE_GL_GLContextType:
                 return "angle-gl";
 #endif
@@ -81,6 +89,8 @@ public:
             case kMESA_GLContextType:
                 return "mesa";
 #endif
+            case kNull_GLContextType:
+                return "null";
             case kDebug_GLContextType:
                 return "debug";
             default:
@@ -124,15 +134,14 @@ public:
      * Get a context initialized with a type of GL context. It also makes the GL context current.
      * Pointer is valid until destroyContexts() is called.
      */
-    ContextInfo* getContextInfo(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard,
+    ContextInfo* getContextInfo(GLContextType type,
                                 GLContextOptions options = kNone_GLContextOptions);
 
     /**
      * Get a GrContext initialized with a type of GL context. It also makes the GL context current.
      */
-    GrContext* get(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard,
-                   GLContextOptions options = kNone_GLContextOptions) {
-        if (ContextInfo* info = this->getContextInfo(type, forcedGpuAPI, options)) {
+    GrContext* get(GLContextType type, GLContextOptions options = kNone_GLContextOptions) {
+        if (ContextInfo* info = this->getContextInfo(type, options)) {
             return info->fGrContext;
         }
         return nullptr;
index e7270c32c47c6283f5d45e4f2be40bb520a0abda..dafa1ef0bc2c61bce33de698df356690ce66350c 100644 (file)
@@ -578,10 +578,7 @@ static void set_current_context_from_interface(const GrGLInterface* interface) {
 }
 #endif
 
-SkNullGLContext* SkNullGLContext::Create(GrGLStandard forcedGpuAPI) {
-    if (kGLES_GrGLStandard == forcedGpuAPI) {
-        return nullptr;
-    }
+SkNullGLContext* SkNullGLContext::Create() {
     SkNullGLContext* ctx = new SkNullGLContext;
     if (!ctx->isValid()) {
         delete ctx;
index 54ef02d492468864f82ee60e89eba16120dabbe9..2c9f38e1d948e342d6e0c946f59d8b5613e68e8c 100644 (file)
@@ -180,7 +180,12 @@ GrGLuint SkANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
 }
 
 SkGLContext* SkANGLEGLContext::createNew() const {
-    SkGLContext* ctx = SkANGLEGLContext::Create(this->gl()->fStandard, fIsGLBackend);
+#ifdef SK_BUILD_FOR_WIN
+    SkGLContext* ctx = fIsGLBackend ? SkANGLEGLContext::CreateOpenGL()
+                                    : SkANGLEGLContext::CreateDirectX();
+#else
+    SkGLContext* ctx = SkANGLEGLContext::CreateOpenGL();
+#endif
     if (ctx) {
         ctx->makeCurrent();
     }
index abbcf559c58af39bfd7678bb3a64874b437e0a3f..113a254e0b7cc611143c2ea0e00d7eb2367e8d35 100644 (file)
@@ -14,10 +14,7 @@ class SkDebugGLContext : public SkGLContext {
 public:
     ~SkDebugGLContext() override;
 
-    static SkDebugGLContext* Create(GrGLStandard forcedGpuAPI) {
-        if (kGLES_GrGLStandard == forcedGpuAPI) {
-            return nullptr;
-        }
+    static SkDebugGLContext* Create() {
         return new SkDebugGLContext;
     }
 private:
index a58f1c890ee92cf05834f9f851524ef9e86da354..a9c77a81da41d0149e3f0d94a9952c18022da5fc 100644 (file)
@@ -19,10 +19,7 @@ private:
 public:
     ~SkMesaGLContext() override;
 
-    static SkMesaGLContext* Create(GrGLStandard forcedGpuAPI) {
-        if (kGLES_GrGLStandard == forcedGpuAPI) {
-            return nullptr;
-        }
+    static SkMesaGLContext* Create() {
         SkMesaGLContext* ctx = new SkMesaGLContext;
         if (!ctx->isValid()) {
             delete ctx;
index 9fa8dafda61f9bd9ab0d83d0622a9f2c5d093474..065abf662b5b0670804067691c7ce9f9a6b1b3f0 100644 (file)
@@ -435,17 +435,21 @@ DEF_GPUTEST(GLPrograms, reporter, factory) {
                 return;
             }
 #if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
             if (type == GrContextFactory::kANGLE_GLContextType) {
                 maxStages = 2;
             }
 #endif
+#endif
 #if SK_COMMAND_BUFFER
+#ifdef SK_BUILD_FOR_WIN
             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
             // TODO(hendrikw): This only needs to happen with the ANGLE comand buffer backend.
             if (type == GrContextFactory::kCommandBuffer_GLContextType) {
                 maxStages = 2;
             }
+#endif
 #endif
             REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(context, maxStages));
         }
index 50bdedff9ec7d8d7c1743ffd764797b45635e70d..1b19ac68e39bf19793353506109f2383455f7ea3 100644 (file)
@@ -17,10 +17,14 @@ DEF_GPUTEST(GrContextFactory_NVPRContextOptionHasPathRenderingSupport, reporter,
     // Test that if NVPR is requested, the context always has path rendering
     // or the context creation fails.
     GrContextFactory testFactory;
-    GrContext* context = testFactory.get(GrContextFactory::kNative_GLContextType,
-                                         kNone_GrGLStandard,
-                                         GrContextFactory::kEnableNVPR_GLContextOptions);
-    if (context) {
+    // Test that if NVPR is possible, caps are in sync.
+    for (int i = 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
+        GrContextFactory::GLContextType glCtxType = static_cast<GrContextFactory::GLContextType>(i);
+        GrContext* context = testFactory.get(glCtxType,
+                                             GrContextFactory::kEnableNVPR_GLContextOptions);
+        if (!context) {
+            continue;
+        }
         REPORTER_ASSERT(
             reporter,
             context->caps()->shaderCaps()->pathRenderingSupport());
index f621dc96aff6c56f080351623b50b02bed1f08ca..9e41c48c845d689c740d1544c731a1652750f44c 100644 (file)
@@ -201,9 +201,62 @@ DEF_TEST(String_SkStrSplit, r) {
 
     results.reset();
     SkStrSplit("\n", "\n", &results);
-    REPORTER_ASSERT(r, results.count() == 1);
+    REPORTER_ASSERT(r, results.count() == 0);
 
     results.reset();
     SkStrSplit("", "\n", &results);
     REPORTER_ASSERT(r, results.count() == 0);
+
+    results.reset();
+    SkStrSplit("a", "\n", &results);
+    REPORTER_ASSERT(r, results.count() == 1);
+    REPORTER_ASSERT(r, results[0].equals("a"));
+}
+DEF_TEST(String_SkStrSplit_All, r) {
+    SkTArray<SkString> results;
+    SkStrSplit("a-_b_c-dee--f-_-_-g-", "-_", kStrict_SkStrSplitMode, &results);
+    REPORTER_ASSERT(r, results.count() == 13);
+    REPORTER_ASSERT(r, results[0].equals("a"));
+    REPORTER_ASSERT(r, results[1].equals(""));
+    REPORTER_ASSERT(r, results[2].equals("b"));
+    REPORTER_ASSERT(r, results[3].equals("c"));
+    REPORTER_ASSERT(r, results[4].equals("dee"));
+    REPORTER_ASSERT(r, results[5].equals(""));
+    REPORTER_ASSERT(r, results[6].equals("f"));
+    REPORTER_ASSERT(r, results[7].equals(""));
+    REPORTER_ASSERT(r, results[8].equals(""));
+    REPORTER_ASSERT(r, results[9].equals(""));
+    REPORTER_ASSERT(r, results[10].equals(""));
+    REPORTER_ASSERT(r, results[11].equals("g"));
+    REPORTER_ASSERT(r, results[12].equals(""));
+
+    results.reset();
+    SkStrSplit("\n", "\n", kStrict_SkStrSplitMode, &results);
+    REPORTER_ASSERT(r, results.count() == 2);
+    REPORTER_ASSERT(r, results[0].equals(""));
+    REPORTER_ASSERT(r, results[1].equals(""));
+
+    results.reset();
+    SkStrSplit("", "\n", kStrict_SkStrSplitMode, &results);
+    REPORTER_ASSERT(r, results.count() == 0);
+
+    results.reset();
+    SkStrSplit("a", "\n", kStrict_SkStrSplitMode, &results);
+    REPORTER_ASSERT(r, results.count() == 1);
+    REPORTER_ASSERT(r, results[0].equals("a"));
+
+    results.reset();
+    SkStrSplit(",,", ",", kStrict_SkStrSplitMode, &results);
+    REPORTER_ASSERT(r, results.count() == 3);
+    REPORTER_ASSERT(r, results[0].equals(""));
+    REPORTER_ASSERT(r, results[1].equals(""));
+    REPORTER_ASSERT(r, results[2].equals(""));
+
+    results.reset();
+    SkStrSplit(",a,b,", ",", kStrict_SkStrSplitMode, &results);
+    REPORTER_ASSERT(r, results.count() == 4);
+    REPORTER_ASSERT(r, results[0].equals(""));
+    REPORTER_ASSERT(r, results[1].equals("a"));
+    REPORTER_ASSERT(r, results[2].equals("b"));
+    REPORTER_ASSERT(r, results[3].equals(""));
 }
diff --git a/tests/TestConfigParsing.cpp b/tests/TestConfigParsing.cpp
new file mode 100644 (file)
index 0000000..825615e
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCommonFlagsConfig.h"
+#include "Test.h"
+#include <initializer_list>
+
+namespace {
+// The code
+//   SkCommandLineFlags::StringArray FLAGS_config1 = make_string_array({"a", "b"})
+// can be used to construct string array that one gets with command line flags.
+// For example, the call above is equivalent of
+//   DEFINE_string(config1, "a b", "");
+// in cases where the default command line flag value ("a b") is used.
+// make_string_array can be used to construct StringArray strings that have spaces in
+// them.
+SkCommandLineFlags::StringArray make_string_array(std::initializer_list<const char*> strings) {
+    SkTArray<SkString> array;
+    for (auto& s : strings) {
+        array.push_back(SkString(s));
+    }
+    return SkCommandLineFlags::StringArray(array);
+}
+}
+DEF_TEST(ParseConfigs_Gpu, reporter) {
+    // Parses a normal config and returns correct "tag".
+    // Gpu config defaults work.
+    SkCommandLineFlags::StringArray config1 = make_string_array({"gpu"});
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+
+    REPORTER_ASSERT(reporter, configs.count() == 1);
+    REPORTER_ASSERT(reporter, configs[0]->getTag().equals("gpu"));
+    REPORTER_ASSERT(reporter, configs[0]->getViaParts().count() == 0);
+#if SK_SUPPORT_GPU
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getContextType()
+                    == GrContextFactory::kNative_GLContextType);
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseNVPR() == false);
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseDIText() == false);
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getSamples() == 0);
+#endif
+}
+
+DEF_TEST(ParseConfigs_OutParam, reporter) {
+    // Clears the out parameter.
+    SkCommandLineFlags::StringArray config1 = make_string_array({"gpu"});
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+    REPORTER_ASSERT(reporter, configs.count() == 1);
+    REPORTER_ASSERT(reporter, configs[0]->getTag().equals("gpu"));
+    SkCommandLineFlags::StringArray config2 = make_string_array({"8888"});
+    ParseConfigs(config2, &configs);
+    REPORTER_ASSERT(reporter, configs.count() == 1);
+    REPORTER_ASSERT(reporter, configs[0]->getTag().equals("8888"));
+}
+
+DEF_TEST(ParseConfigs_DefaultConfigs, reporter) {
+    // Parses all default configs and returns correct "tag".
+
+    SkCommandLineFlags::StringArray config1 = make_string_array({
+        "565", "8888", "debug", "gpu", "gpudebug", "gpudft", "gpunull", "msaa16", "msaa4",
+        "nonrendering", "null", "nullgpu", "nvprmsaa16", "nvprmsaa4", "pdf", "pdf_poppler",
+        "skp", "svg", "xps", "angle", "angle-gl", "commandbuffer", "mesa", "hwui"
+    });
+
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+
+    REPORTER_ASSERT(reporter, configs.count() == config1.count());
+    for (int i = 0; i < config1.count(); ++i) {
+        REPORTER_ASSERT(reporter, configs[i]->getTag().equals(config1[i]));
+        REPORTER_ASSERT(reporter, configs[i]->getViaParts().count() == 0);
+    }
+#if SK_SUPPORT_GPU
+    REPORTER_ASSERT(reporter, !configs[0]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[1]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[2]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[3]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[4]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[5]->asConfigGpu()->getUseDIText());
+    REPORTER_ASSERT(reporter, configs[6]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[7]->asConfigGpu()->getSamples() == 16);
+    REPORTER_ASSERT(reporter, configs[8]->asConfigGpu()->getSamples() == 4);
+    REPORTER_ASSERT(reporter, !configs[9]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[10]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[11]->asConfigGpu());
+    REPORTER_ASSERT(reporter, configs[12]->asConfigGpu()->getSamples() == 16);
+    REPORTER_ASSERT(reporter, configs[12]->asConfigGpu()->getUseNVPR());
+    REPORTER_ASSERT(reporter, configs[13]->asConfigGpu()->getSamples() == 4);
+    REPORTER_ASSERT(reporter, configs[13]->asConfigGpu()->getUseNVPR());
+    REPORTER_ASSERT(reporter, !configs[14]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[15]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[16]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[17]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[18]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[23]->asConfigGpu());
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    REPORTER_ASSERT(reporter, configs[19]->asConfigGpu());
+#else
+    REPORTER_ASSERT(reporter, !configs[19]->asConfigGpu());
+#endif
+    REPORTER_ASSERT(reporter, configs[20]->asConfigGpu());
+#else
+    REPORTER_ASSERT(reporter, !configs[19]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[20]->asConfigGpu());
+#endif
+#if SK_COMMAND_BUFFER
+    REPORTER_ASSERT(reporter, configs[21]->asConfigGpu());
+#else
+    REPORTER_ASSERT(reporter, !configs[21]->asConfigGpu());
+#endif
+#if SK_MESA
+    REPORTER_ASSERT(reporter, configs[22]->asConfigGpu());
+#else
+    REPORTER_ASSERT(reporter, !configs[22]->asConfigGpu());
+#endif
+#endif
+}
+
+DEF_TEST(ParseConfigs_ExtendedGpuConfigsCorrect, reporter) {
+    SkCommandLineFlags::StringArray config1 = make_string_array({
+        "gpu(nvpr=true,dit=true)",
+        "gpu(api=angle)",
+        "gpu(api=angle-gl)",
+        "gpu(api=mesa,samples=77)",
+        "gpu(dit=true,api=commandbuffer)",
+        "gpu()",
+        "gpu(api=gles)"
+    });
+
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+    REPORTER_ASSERT(reporter, configs.count() == config1.count());
+    for (int i = 0; i < config1.count(); ++i) {
+        REPORTER_ASSERT(reporter, configs[i]->getTag().equals(config1[i]));
+    }
+#if SK_SUPPORT_GPU
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kNative_GLContextType);
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseNVPR());
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getUseDIText());
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu()->getSamples() == 0);
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    REPORTER_ASSERT(reporter, configs[1]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kANGLE_GLContextType);
+#else
+    REPORTER_ASSERT(reporter, !configs[1]->asConfigGpu());
+#endif
+    REPORTER_ASSERT(reporter, configs[2]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kANGLE_GL_GLContextType);
+#else
+    REPORTER_ASSERT(reporter, !configs[1]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[2]->asConfigGpu());
+#endif
+#if SK_MESA
+    REPORTER_ASSERT(reporter, configs[3]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kMESA_GLContextType);
+#else
+    REPORTER_ASSERT(reporter, !configs[3]->asConfigGpu());
+#endif
+#if SK_COMMAND_BUFFER
+    REPORTER_ASSERT(reporter, configs[4]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kCommandBuffer_GLContextType);
+
+#else
+    REPORTER_ASSERT(reporter, !configs[4]->asConfigGpu());
+#endif
+    REPORTER_ASSERT(reporter, configs[5]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kNative_GLContextType);
+    REPORTER_ASSERT(reporter, !configs[5]->asConfigGpu()->getUseNVPR());
+    REPORTER_ASSERT(reporter, !configs[5]->asConfigGpu()->getUseDIText());
+    REPORTER_ASSERT(reporter, configs[5]->asConfigGpu()->getSamples() == 0);
+    REPORTER_ASSERT(reporter, configs[6]->asConfigGpu()->getContextType() ==
+                    GrContextFactory::kGLES_GLContextType);
+    REPORTER_ASSERT(reporter, !configs[6]->asConfigGpu()->getUseNVPR());
+    REPORTER_ASSERT(reporter, !configs[6]->asConfigGpu()->getUseDIText());
+    REPORTER_ASSERT(reporter, configs[6]->asConfigGpu()->getSamples() == 0);
+
+#endif
+}
+
+DEF_TEST(ParseConfigs_ExtendedGpuConfigsIncorrect, reporter) {
+    SkCommandLineFlags::StringArray config1 = make_string_array({
+        "gpu(nvpr=1)", // Number as bool.
+        "gpu(api=gl,)", // Trailing in comma.
+        "gpu(api=angle-glu)", // Unknown api.
+        "gpu(api=,samples=0)", // Empty api.
+        "gpu(samples=true)", // Value true as a number.
+        "gpu(samples=0,samples=0)", // Duplicate option key.
+        "gpu(,samples=0)", // Leading comma.
+        "gpu(samples=54", // Missing closing parenthesis.
+        ",,",
+        "gpu(", // Missing parenthesis.
+        "samples=54" // No backend.
+        "gpu(nvpr=true )", // Space.
+    });
+
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+    REPORTER_ASSERT(reporter, configs.count() == config1.count());
+    for (int i = 0; i < config1.count(); ++i) {
+        REPORTER_ASSERT(reporter, configs[i]->getTag().equals(config1[i]));
+#if SK_SUPPORT_GPU
+        REPORTER_ASSERT(reporter, !configs[i]->asConfigGpu());
+#endif
+    }
+}
+
+
+DEF_TEST(ParseConfigs_ExtendedGpuConfigsSurprises, reporter) {
+    // These just list explicitly some properties of the system.
+    SkCommandLineFlags::StringArray config1 = make_string_array({
+        // Options are not canonized -> two same configs have a different tag.
+        "gpu(nvpr=true,dit=true)", "gpu(dit=true,nvpr=true)",
+        // API native is alias for gl or gles, but it's not canonized -> different tag.
+        "gpu(api=native)", "gpu(api=gl)", "gpu(api=gles)", ""
+        // Default values are not canonized -> different tag.
+        "gpu", "gpu()", "gpu(samples=0)", "gpu(api=native,samples=0)"
+    });
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+    REPORTER_ASSERT(reporter, configs.count() == config1.count());
+    for (int i = 0; i < config1.count(); ++i) {
+        REPORTER_ASSERT(reporter, configs[i]->getTag().equals(config1[i]));
+#if SK_SUPPORT_GPU
+        REPORTER_ASSERT(reporter, configs[i]->asConfigGpu());
+#endif
+    }
+}
+DEF_TEST(ParseConfigs_ViaParsing, reporter) {
+    SkCommandLineFlags::StringArray config1 = make_string_array({
+        "a-b-c-8888",
+        "zz-qq-gpu",
+        "a-angle-gl"
+    });
+
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+    const struct {
+        const char* tag;
+        const char* vias[3];
+    } expectedConfigs[] = {
+        {"8888", {"a", "b", "c"}},
+        {"gpu", {"zz", "qq", nullptr}},
+        {"angle-gl", {"a", nullptr, nullptr}}  // The angle-gl tag is only tag that contains
+                                                 // hyphen.
+    };
+    for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(expectedConfigs)); ++i) {
+        REPORTER_ASSERT(reporter, configs[i]->getTag().equals(expectedConfigs[i].tag));
+        for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(expectedConfigs[i].vias)); ++j) {
+            if (!expectedConfigs[i].vias[j]) {
+                REPORTER_ASSERT(reporter, configs[i]->getViaParts().count() == j);
+                break;
+            }
+            REPORTER_ASSERT(reporter,
+                            configs[i]->getViaParts()[j].equals(expectedConfigs[i].vias[j]));
+        }
+    }
+}
+
+DEF_TEST(ParseConfigs_ViaParsingExtendedForm, reporter) {
+    SkCommandLineFlags::StringArray config1 = make_string_array({
+        "zz-qq-gpu(api=gles)",
+        "a-gpu(samples=1",
+        "abc-def-angle-gl(samples=1)",
+    });
+
+    SkCommandLineConfigArray configs;
+    ParseConfigs(config1, &configs);
+    const struct {
+        const char* tag;
+        const char* vias[3];
+    } expectedConfigs[] = {
+        {"gpu(api=gles)", {"zz", "qq", nullptr}},
+        {"gpu(samples=1", {"a", nullptr, nullptr}}, // This is not extended form, but via still
+                                                    // works as expected.
+        {"gl(samples=1)", {"abc", "def", "angle"}}  // This is not extended form.
+                                                    // Also angle-gl is not a "tag" in this case.
+    };
+    for (int i = 0; i < static_cast<int>(SK_ARRAY_COUNT(expectedConfigs)); ++i) {
+        REPORTER_ASSERT(reporter, configs[i]->getTag().equals(expectedConfigs[i].tag));
+        for (int j = 0; j < static_cast<int>(SK_ARRAY_COUNT(expectedConfigs[i].vias)); ++j) {
+            if (!expectedConfigs[i].vias[j]) {
+                REPORTER_ASSERT(reporter, configs[i]->getViaParts().count() ==
+                                static_cast<int>(j));
+                break;
+            }
+            REPORTER_ASSERT(reporter,
+                            configs[i]->getViaParts()[j].equals(expectedConfigs[i].vias[j]));
+        }
+    }
+#if SK_SUPPORT_GPU
+    REPORTER_ASSERT(reporter, configs[0]->asConfigGpu());
+    REPORTER_ASSERT(reporter, !configs[1]->asConfigGpu());
+#endif
+}
index 9b2c9616cbf4ebc0a70c4bfc33cc98910053bc4d..cddf9fb0b35cc5907f55740391f32bf774cab561 100644 (file)
@@ -22,8 +22,10 @@ template <typename T> static void ignore_result(const T&) {}
 
 bool SkFlagInfo::CreateStringFlag(const char* name, const char* shortName,
                                   SkCommandLineFlags::StringArray* pStrings,
-                                  const char* defaultValue, const char* helpString) {
-    SkFlagInfo* info = new SkFlagInfo(name, shortName, kString_FlagType, helpString);
+                                  const char* defaultValue, const char* helpString,
+                                  const char* extendedHelpString) {
+    SkFlagInfo* info = new SkFlagInfo(name, shortName, kString_FlagType, helpString,
+                                      extendedHelpString);
     info->fDefaultString.set(defaultValue);
 
     info->fStrings = pStrings;
@@ -151,29 +153,16 @@ void SkCommandLineFlags::SetUsage(const char* usage) {
 // Maximum line length for the help message.
 #define LINE_LENGTH 72
 
-static void print_help_for_flag(const SkFlagInfo* flag) {
-    SkDebugf("    --%s", flag->name().c_str());
-    const SkString& shortName = flag->shortName();
-    if (shortName.size() > 0) {
-        SkDebugf(" or -%s", shortName.c_str());
-    }
-    SkDebugf(":\ttype: %s", flag->typeAsString().c_str());
-    if (flag->defaultValue().size() > 0) {
-        SkDebugf("\tdefault: %s", flag->defaultValue().c_str());
-    }
-    SkDebugf("\n");
-    const SkString& help = flag->help();
-    size_t length = help.size();
-    const char* currLine = help.c_str();
+static void print_indented(const SkString& text) {
+    size_t length = text.size();
+    const char* currLine = text.c_str();
     const char* stop = currLine + length;
     while (currLine < stop) {
-        if (strlen(currLine) < LINE_LENGTH) {
-            // Only one line length's worth of text left.
-            SkDebugf("        %s\n", currLine);
-            break;
-        }
         int lineBreak = SkStrFind(currLine, "\n");
-        if (lineBreak < 0 || lineBreak > LINE_LENGTH) {
+        if (lineBreak < 0) {
+            lineBreak = static_cast<int>(strlen(currLine));
+        }
+        if (lineBreak > LINE_LENGTH) {
             // No line break within line length. Will need to insert one.
             // Find a space before the line break.
             int spaceIndex = LINE_LENGTH - 1;
@@ -198,6 +187,26 @@ static void print_help_for_flag(const SkFlagInfo* flag) {
             currLine += lineBreak;
         }
     }
+}
+
+static void print_help_for_flag(const SkFlagInfo* flag) {
+    SkDebugf("    --%s", flag->name().c_str());
+    const SkString& shortName = flag->shortName();
+    if (shortName.size() > 0) {
+        SkDebugf(" or -%s", shortName.c_str());
+    }
+    SkDebugf(":\ttype: %s", flag->typeAsString().c_str());
+    if (flag->defaultValue().size() > 0) {
+        SkDebugf("\tdefault: %s", flag->defaultValue().c_str());
+    }
+    SkDebugf("\n");
+    const SkString& help = flag->help();
+    print_indented(help);
+    SkDebugf("\n");
+}
+static void print_extended_help_for_flag(const SkFlagInfo* flag) {
+    print_help_for_flag(flag);
+    print_indented(flag->extendedHelp());
     SkDebugf("\n");
 }
 
@@ -248,6 +257,10 @@ void SkCommandLineFlags::Parse(int argc, char** argv) {
                          CompareFlagsByName());
                 for (int i = 0; i < allFlags.count(); ++i) {
                     print_help_for_flag(allFlags[i]);
+                    if (allFlags[i]->extendedHelp().size() > 0) {
+                        SkDebugf("        Use '--help %s' for more information.\n",
+                                 allFlags[i]->name().c_str());
+                    }
                 }
             } else {
                 for (SkFlagInfo* flag = SkCommandLineFlags::gHead; flag;
@@ -255,7 +268,7 @@ void SkCommandLineFlags::Parse(int argc, char** argv) {
                     for (int k = 0; k < helpFlags.count(); k++) {
                         if (flag->name().equals(helpFlags[k]) ||
                             flag->shortName().equals(helpFlags[k])) {
-                            print_help_for_flag(flag);
+                            print_extended_help_for_flag(flag);
                             helpFlags.remove(k);
                             break;
                         }
index 5909413523143f87fd9d25eab0d565a37d82c082..909718d3e79fa404c273541d4db89455176821e9 100644 (file)
  *  as its value. All strings that follow the flag on the command line (until
  *  a string that begins with '-') will be entries in the array.
  *
+ *  DEFINE_extended_string(args, .., .., extendedHelpString);
+ *
+ *  creates a similar string array flag as DEFINE_string. The flag will have extended help text
+ *  (extendedHelpString) that can the user can see with '--help <args>' flag.
+ *
  *  Any flag can be referenced from another file after using the following:
  *
  *  DECLARE_x(name);
@@ -114,6 +119,10 @@ public:
      */
     class StringArray {
     public:
+        StringArray() { }
+        explicit StringArray(const SkTArray<SkString>& strings)
+            : fStrings(strings) {
+        }
         const char* operator[](int i) const {
             SkASSERT(i >= 0 && i < fStrings.count());
             return fStrings[i].c_str();
@@ -204,7 +213,15 @@ SK_UNUSED static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(nam
                                                                    nullptr,              \
                                                                    &FLAGS_##name,     \
                                                                    defaultValue,      \
-                                                                   helpString)
+                                                                   helpString, nullptr)
+#define DEFINE_extended_string(name, defaultValue, helpString, extendedHelpString) \
+SkCommandLineFlags::StringArray FLAGS_##name;                                      \
+SK_UNUSED static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(name),   \
+                                                                   nullptr, \
+                                                                   &FLAGS_##name, \
+                                                                   defaultValue, \
+                                                                   helpString, \
+                                                                   extendedHelpString)
 
 // string2 allows specifying a short name. There is an assert that shortName
 // is only 1 character.
@@ -214,7 +231,7 @@ SK_UNUSED static bool unused_##name = SkFlagInfo::CreateStringFlag(TO_STRING(nam
                                                                    TO_STRING(shortName),  \
                                                                    &FLAGS_##name,         \
                                                                    defaultValue,          \
-                                                                   helpString)
+                                                                   helpString, nullptr)
 
 #define DECLARE_string(name) extern SkCommandLineFlags::StringArray FLAGS_##name;
 
@@ -273,7 +290,7 @@ public:
      */
     static bool CreateBoolFlag(const char* name, const char* shortName, bool* pBool,
                                bool defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, shortName, kBool_FlagType, helpString);
+        SkFlagInfo* info = new SkFlagInfo(name, shortName, kBool_FlagType, helpString, nullptr);
         info->fBoolValue = pBool;
         *info->fBoolValue = info->fDefaultBool = defaultValue;
         return true;
@@ -287,14 +304,15 @@ public:
      */
     static bool CreateStringFlag(const char* name, const char* shortName,
                                  SkCommandLineFlags::StringArray* pStrings,
-                                 const char* defaultValue, const char* helpString);
+                                 const char* defaultValue, const char* helpString,
+                                 const char* extendedHelpString);
 
     /**
      *  See comments for CreateBoolFlag.
      */
     static bool CreateIntFlag(const char* name, int32_t* pInt,
                               int32_t defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kInt_FlagType, helpString);
+        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kInt_FlagType, helpString, nullptr);
         info->fIntValue = pInt;
         *info->fIntValue = info->fDefaultInt = defaultValue;
         return true;
@@ -302,7 +320,7 @@ public:
 
     static bool CreateIntFlag(const char* name, const char* shortName, int32_t* pInt,
                               int32_t defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, shortName, kInt_FlagType, helpString);
+        SkFlagInfo* info = new SkFlagInfo(name, shortName, kInt_FlagType, helpString, nullptr);
         info->fIntValue = pInt;
         *info->fIntValue = info->fDefaultInt = defaultValue;
         return true;
@@ -313,7 +331,7 @@ public:
      */
     static bool CreateDoubleFlag(const char* name, double* pDouble,
                                  double defaultValue, const char* helpString) {
-        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kDouble_FlagType, helpString);
+        SkFlagInfo* info = new SkFlagInfo(name, nullptr, kDouble_FlagType, helpString, nullptr);
         info->fDoubleValue = pDouble;
         *info->fDoubleValue = info->fDefaultDouble = defaultValue;
         return true;
@@ -383,6 +401,7 @@ public:
     const SkString& shortName() const { return fShortName; }
 
     const SkString& help() const { return fHelpString; }
+    const SkString& extendedHelp() const { return fExtendedHelpString; }
 
     SkString defaultValue() const {
         SkString result;
@@ -421,11 +440,13 @@ public:
     }
 
 private:
-    SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString)
+    SkFlagInfo(const char* name, const char* shortName, FlagTypes type, const char* helpString,
+               const char* extendedHelpString)
         : fName(name)
         , fShortName(shortName)
         , fFlagType(type)
         , fHelpString(helpString)
+        , fExtendedHelpString(extendedHelpString)
         , fBoolValue(nullptr)
         , fDefaultBool(false)
         , fIntValue(nullptr)
@@ -453,6 +474,7 @@ private:
     SkString             fShortName;
     FlagTypes            fFlagType;
     SkString             fHelpString;
+    SkString             fExtendedHelpString;
     bool*                fBoolValue;
     bool                 fDefaultBool;
     int32_t*             fIntValue;
index 9783dde373546d8f5c47e6b0f340a1a31e32e8e8..a2da1314fc637575764703f2ff0cdd8de524e2ee 100644 (file)
@@ -7,11 +7,6 @@
 
 #include "SkCommonFlags.h"
 
-DEFINE_string(config, "565 8888 gpu nonrendering angle hwui ", "Options: "
-              "565 8888 angle debug gpu gpudebug gpudft gpunull hwui mesa "
-              "msaa16 msaa4 nonrendering null nullgpu nvprmsaa16 nvprmsaa4 "
-              "pdf skp svg xps (and maybe more)");
-
 DEFINE_bool(cpu, true, "master switch for running CPU-bound work.");
 
 DEFINE_bool(dryRun, false,
@@ -19,11 +14,6 @@ DEFINE_bool(dryRun, false,
 
 DEFINE_bool(gpu, true, "master switch for running GPU-bound work.");
 
-DEFINE_string(gpuAPI, "", "Force use of specific gpu API.  Using \"gl\" "
-              "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
-              "Defaults to empty string, which selects the API native to the "
-              "system.");
-
 DEFINE_string(images, "", "Directory of images to decode.");
 
 DEFINE_string2(match, m, nullptr,
index d6fb2c1d9bef62e871dc1ef3d9f3e36f0c7b6e98..ddd8d3a4a2f86022becfefcbdbad9f3fae604048 100644 (file)
 
 #include "SkCommandLineFlags.h"
 
-DECLARE_string(config);
 DECLARE_bool(cpu);
 DECLARE_bool(dryRun);
 DECLARE_bool(gpu);
-DECLARE_string(gpuAPI);
 DECLARE_string(images);
 DECLARE_string(match);
 DECLARE_bool(quiet);
diff --git a/tools/flags/SkCommonFlagsConfig.cpp b/tools/flags/SkCommonFlagsConfig.cpp
new file mode 100644 (file)
index 0000000..82ac493
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCommonFlagsConfig.h"
+
+#include <stdlib.h>
+
+static const char defaultConfigs[] =
+    "565 8888 gpu nonrendering"
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    " angle"
+#endif
+#endif
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    " hwui"
+#endif
+    ;
+
+static const char configHelp[] =
+    "Options: 565 8888 debug gpu gpudebug gpudft gpunull "
+    "msaa16 msaa4 nonrendering null nullgpu nvprmsaa16 nvprmsaa4 "
+    "pdf pdf_poppler skp svg xps"
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    " angle"
+#endif
+    " angle-gl"
+#endif
+#if SK_COMMAND_BUFFER
+    " commandbuffer"
+#endif
+#if SK_MESA
+    " mesa"
+#endif
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    " hwui"
+#endif
+    " or use extended form 'backend(option=value,...)'.\n";
+
+static const char configExtendedHelp[] =
+    "Extended form: 'backend(option=value,...)'\n\n"
+    "Possible backends and options:\n"
+#if SK_SUPPORT_GPU
+    "\n"
+    "gpu(api=string,dit=bool,nvpr=bool,samples=int)\tGPU backend\n"
+    "\tapi\ttype: string\tdefault: native.\n"
+    "\t    Select graphics API to use with gpu backend.\n"
+    "\t    Options:\n"
+    "\t\tnative\t\t\tUse platform default OpenGL or OpenGL ES backend.\n"
+    "\t\tgl    \t\t\tUse OpenGL.\n"
+    "\t\tgles  \t\t\tUse OpenGL ES.\n"
+    "\t\tdebug \t\t\tUse debug OpenGL.\n"
+    "\t\tnull  \t\t\tUse null OpenGL.\n"
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    "\t\tangle\t\t\tUse ANGLE DirectX.\n"
+#endif
+    "\t\tangle-gl\t\t\tUse ANGLE OpenGL.\n"
+#endif
+#if SK_COMMAND_BUFFER
+    "\t\tcommandbuffer\t\tUse command buffer.\n"
+#endif
+#if SK_MESA
+    "\t\tmesa\t\t\tUse MESA.\n"
+#endif
+    "\tdit\ttype: bool\tdefault: false.\n"
+    "\t    Use device independent text.\n"
+    "\tnvpr\ttype: bool\tdefault: false.\n"
+    "\t    Use NV_path_rendering OpenGL and OpenGL ES extension.\n"
+    "\tsamples\ttype: int\tdefault: 0.\n"
+    "\t    Use multisampling with N samples.\n"
+    "\n"
+    "Predefined configs:\n\n"
+    "\tgpu      \t= gpu()\n"
+    "\tmsaa4    \t= gpu(samples=4)\n"
+    "\tmsaa16   \t= gpu(samples=16)\n"
+    "\tnvprmsaa4\t= gpu(nvpr=true,samples=4)\n"
+    "\tnvprmsaa16\t= gpu(nvpr=true,samples=16)\n"
+    "\tgpudft    \t= gpu(dit=true)\n"
+    "\tgpudebug  \t= gpu(api=debug)\n"
+    "\tgpunull   \t= gpu(api=null)\n"
+    "\tdebug     \t= gpu(api=debug)\n"
+    "\tnullgpu   \t= gpu(api=null)\n"
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    "\tangle     \t= gpu(api=angle)\n"
+#endif
+    "\tangle-gl  \t= gpu(api=angle-gl)\n"
+#endif
+#if SK_COMMAND_BUFFER
+    "\tcommandbuffer\t= gpu(api=commandbuffer)\n"
+#endif
+#if SK_MESA
+    "\tmesa      \t= gpu(api=mesa)\n"
+#endif
+#endif
+    ;
+
+DEFINE_extended_string(config, defaultConfigs, configHelp, configExtendedHelp);
+
+static const struct {
+    const char* predefinedConfig;
+    const char* backend;
+    const char* options;
+} gPredefinedConfigs[] = {
+#if SK_SUPPORT_GPU
+    { "gpu",        "gpu", "" },
+    { "msaa4",      "gpu", "samples=4" },
+    { "msaa16",     "gpu", "samples=16" },
+    { "nvprmsaa4",  "gpu", "nvpr=true,samples=4" },
+    { "nvprmsaa16", "gpu", "nvpr=true,samples=16" },
+    { "gpudft",     "gpu", "dit=true" },
+    { "gpudebug",   "gpu", "api=debug" },
+    { "gpunull",    "gpu", "api=null" },
+    { "debug",      "gpu", "api=debug" },
+    { "nullgpu",    "gpu", "api=null" }
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    , { "angle",      "gpu", "api=angle" }
+#endif
+    , { "angle-gl",   "gpu", "api=angle-gl" }
+#endif
+#if SK_COMMAND_BUFFER
+    , { "commandbuffer", "gpu", "api=commandbuffer" }
+#endif
+#if SK_MESA
+    , { "mesa", "gpu", "api=mesa" }
+#endif
+#else
+    { "", "", "" }
+#endif
+};
+
+SkCommandLineConfig::SkCommandLineConfig(const SkString& tag, const SkTArray<SkString>& viaParts)
+        : fTag(tag)
+        , fViaParts(viaParts) {
+}
+SkCommandLineConfig::~SkCommandLineConfig() {
+}
+
+#if SK_SUPPORT_GPU
+SkCommandLineConfigGpu::SkCommandLineConfigGpu(
+    const SkString& tag, const SkTArray<SkString>& viaParts,
+    ContextType contextType, bool useNVPR, bool useDIText, int samples)
+        : SkCommandLineConfig(tag, viaParts)
+        , fContextType(contextType)
+        , fUseNVPR(useNVPR)
+        , fUseDIText(useDIText)
+        , fSamples(samples) {
+}
+static bool parse_option_int(const SkString& value, int* outInt) {
+    if (value.isEmpty()) {
+        return false;
+    }
+    char* endptr = nullptr;
+    long intValue = strtol(value.c_str(), &endptr, 10);
+    if (*endptr != '\0') {
+        return false;
+    }
+    *outInt = static_cast<int>(intValue);
+    return true;
+}
+static bool parse_option_bool(const SkString& value, bool* outBool) {
+    if (value.equals("true")) {
+        *outBool = true;
+        return true;
+    }
+    if (value.equals("false")) {
+        *outBool = false;
+        return true;
+    }
+    return false;
+}
+static bool parse_option_gpu_api(const SkString& value,
+                                 SkCommandLineConfigGpu::ContextType* outContextType) {
+    if (value.equals("native")) {
+        *outContextType = GrContextFactory::kNative_GLContextType;
+        return true;
+    }
+    if (value.equals("gl")) {
+        *outContextType = GrContextFactory::kGL_GLContextType;
+        return true;
+    }
+    if (value.equals("gles")) {
+        *outContextType = GrContextFactory::kGLES_GLContextType;
+        return true;
+    }
+    if (value.equals("debug")) {
+        *outContextType = GrContextFactory::kDebug_GLContextType;
+        return true;
+    }
+    if (value.equals("null")) {
+        *outContextType = GrContextFactory::kNull_GLContextType;
+        return true;
+    }
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+    if (value.equals("angle")) {
+        *outContextType = GrContextFactory::kANGLE_GLContextType;
+        return true;
+    }
+#endif
+    if (value.equals("angle-gl")) {
+        *outContextType = GrContextFactory::kANGLE_GL_GLContextType;
+        return true;
+    }
+#endif
+#if SK_COMMAND_BUFFER
+    if (value.equals("commandbuffer")) {
+        *outContextType = GrContextFactory::kCommandBuffer_GLContextType;
+        return true;
+    }
+#endif
+#if SK_MESA
+    if (value.equals("mesa")) {
+        *outContextType = GrContextFactory::kMESA_GLContextType;
+        return true;
+    }
+#endif
+    return false;
+}
+
+SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
+                                                      const SkTArray<SkString>& vias,
+                                                      const SkString& options) {
+    // Defaults for GPU backend.
+    bool seenAPI = false;
+    SkCommandLineConfigGpu::ContextType contextType = GrContextFactory::kNative_GLContextType;
+    bool seenUseNVPR = false;
+    bool useNVPR = false;
+    bool seenUseDIText =false;
+    bool useDIText = false;
+    bool seenSamples = false;
+    int samples = 0;
+
+    SkTArray<SkString> optionParts;
+    SkStrSplit(options.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
+    for (int i = 0; i < optionParts.count(); ++i) {
+        SkTArray<SkString> keyValueParts;
+        SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
+        if (keyValueParts.count() != 2) {
+            return nullptr;
+        }
+        const SkString& key = keyValueParts[0];
+        const SkString& value = keyValueParts[1];
+        bool valueOk = false;
+        if (key.equals("api") && !seenAPI) {
+            valueOk = parse_option_gpu_api(value, &contextType);
+            seenAPI = true;
+        } else if (key.equals("nvpr") && !seenUseNVPR) {
+            valueOk = parse_option_bool(value, &useNVPR);
+            seenUseNVPR = true;
+        } else if (key.equals("dit") && !seenUseDIText) {
+            valueOk = parse_option_bool(value, &useDIText);
+            seenUseDIText = true;
+        } else if (key.equals("samples") && !seenSamples) {
+            valueOk = parse_option_int(value, &samples);
+            seenSamples = true;
+        }
+        if (!valueOk) {
+            return nullptr;
+        }
+    }
+    return new SkCommandLineConfigGpu(tag, vias, contextType, useNVPR, useDIText, samples);
+}
+#endif
+
+void ParseConfigs(const SkCommandLineFlags::StringArray& configs,
+                  SkCommandLineConfigArray* outResult) {
+    outResult->reset();
+    for (int i = 0; i < configs.count(); ++i) {
+        SkString extendedConfigBackend;
+        SkString extendedConfigOptions;
+        SkString tag(configs[i]);
+        SkTArray<SkString> vias;
+
+        SkTArray<SkString> parts;
+        SkStrSplit(tag.c_str(), "(", kStrict_SkStrSplitMode, &parts);
+        if (parts.count() == 2) {
+            SkTArray<SkString> parts2;
+            SkStrSplit(parts[1].c_str(), ")", kStrict_SkStrSplitMode, &parts2);
+            if (parts2.count() == 2 && parts2[1].isEmpty()) {
+                SkStrSplit(parts[0].c_str(), "-", kStrict_SkStrSplitMode, &vias);
+                if (vias.count()) {
+                    extendedConfigBackend = vias[vias.count() - 1];
+                    vias.pop_back();
+                } else {
+                    extendedConfigBackend = parts[0];
+                }
+                extendedConfigOptions = parts2[0];
+                tag.printf("%s(%s)", extendedConfigBackend.c_str(), extendedConfigOptions.c_str());
+            }
+        }
+        if (extendedConfigBackend.isEmpty()) {
+            SkStrSplit(tag.c_str(), "-", kStrict_SkStrSplitMode, &vias);
+            if (vias.count()) {
+                tag = vias[vias.count() - 1];
+                vias.pop_back();
+            }
+            // Note: no #if SK_ANGLE: this is a special rule in the via-tag grammar.
+            if (vias.count() && tag.equals("gl") && vias[vias.count() - 1].equals("angle")) {
+                tag = "angle-gl";
+                vias.pop_back();
+            }
+        }
+        if (extendedConfigBackend.isEmpty()) {
+            for (auto& predefinedConfig : gPredefinedConfigs) {
+                if (tag.equals(predefinedConfig.predefinedConfig)) {
+                    extendedConfigBackend = predefinedConfig.backend;
+                    extendedConfigOptions = predefinedConfig.options;
+                    break;
+                }
+            }
+        }
+
+        SkCommandLineConfig* parsedConfig = nullptr;
+#if SK_SUPPORT_GPU
+        if (extendedConfigBackend.equals("gpu")) {
+            parsedConfig = parse_command_line_config_gpu(tag, vias, extendedConfigOptions);
+        }
+#endif
+        if (!parsedConfig) {
+            parsedConfig = new SkCommandLineConfig(tag, vias);
+        }
+        outResult->emplace_back(parsedConfig);
+    }
+}
diff --git a/tools/flags/SkCommonFlagsConfig.h b/tools/flags/SkCommonFlagsConfig.h
new file mode 100644 (file)
index 0000000..54a0769
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SK_COMMON_FLAGS_CONFIG_H
+#define SK_COMMON_FLAGS_CONFIG_H
+
+#include "SkCommandLineFlags.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#endif
+
+DECLARE_string(config);
+
+#if SK_SUPPORT_GPU
+class SkCommandLineConfigGpu;
+#endif
+
+// SkCommandLineConfig represents a Skia rendering configuration string.
+// The string has following form:
+//   [via-]*tag
+// where 'tag' consists of chars excluding hyphen or "angle-gl"
+// and each 'via' consists of chars excluding hyphen.
+class SkCommandLineConfig {
+  public:
+    SkCommandLineConfig(const SkString& tag, const SkTArray<SkString>& viaParts);
+    virtual ~SkCommandLineConfig();
+#if SK_SUPPORT_GPU
+    virtual const SkCommandLineConfigGpu* asConfigGpu() const { return nullptr; }
+#endif
+    const SkString& getTag() const { return fTag; }
+    const SkTArray<SkString>& getViaParts() const { return fViaParts; }
+  private:
+    SkString fTag;
+    SkTArray<SkString> fViaParts;
+};
+
+#if SK_SUPPORT_GPU
+// SkCommandLineConfigGpu is a SkCommandLineConfig that extracts information out of the tag.  It is
+// constructed configs that have:
+// * tags of form "gpu(option=value,option2=value,...)"
+// * tags that represent a shorthand of above (such as "msaa16" representing "gpu(samples=16)")
+class SkCommandLineConfigGpu : public SkCommandLineConfig {
+  public:
+    typedef GrContextFactory::GLContextType ContextType;
+    SkCommandLineConfigGpu(const SkString& tag, const SkTArray<SkString>& viaParts,
+                           ContextType contextType, bool useNVPR, bool useDIText, int samples);
+    const SkCommandLineConfigGpu* asConfigGpu() const override { return this; }
+    ContextType getContextType() const { return fContextType; }
+    bool getUseNVPR() const { return fUseNVPR; }
+    bool getUseDIText() const { return fUseDIText; }
+    int getSamples() const { return fSamples; }
+
+  private:
+    ContextType fContextType;
+    bool fUseNVPR;
+    bool fUseDIText;
+    int fSamples;
+};
+#endif
+
+typedef SkTArray<SkAutoTDelete<SkCommandLineConfig>, true> SkCommandLineConfigArray;
+void ParseConfigs(const SkCommandLineFlags::StringArray& configList,
+                  SkCommandLineConfigArray* outResult);
+
+#endif