aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/nanobench.cpp14
-rw-r--r--dm/DM.cpp169
-rw-r--r--dm/DMGpuSupport.h6
-rw-r--r--dm/DMSrcSink.cpp5
-rw-r--r--dm/DMSrcSink.h3
-rw-r--r--gyp/flags.gyp8
-rw-r--r--include/core/SkString.h17
-rw-r--r--include/gpu/gl/SkNullGLContext.h7
-rw-r--r--include/gpu/gl/angle/SkANGLEGLContext.h15
-rw-r--r--include/gpu/gl/command_buffer/SkCommandBufferGLContext.h5
-rw-r--r--src/core/SkString.cpp33
-rwxr-xr-xsrc/gpu/GrContextFactory.cpp33
-rw-r--r--src/gpu/GrContextFactory.h35
-rw-r--r--src/gpu/gl/SkNullGLContext.cpp5
-rw-r--r--src/gpu/gl/angle/SkANGLEGLContext.cpp7
-rw-r--r--src/gpu/gl/debug/SkDebugGLContext.h5
-rw-r--r--src/gpu/gl/mesa/SkMesaGLContext.h5
-rw-r--r--tests/GLProgramsTest.cpp4
-rw-r--r--tests/GrContextFactoryTest.cpp12
-rw-r--r--tests/StringTest.cpp55
-rw-r--r--tests/TestConfigParsing.cpp303
-rw-r--r--tools/flags/SkCommandLineFlags.cpp59
-rw-r--r--tools/flags/SkCommandLineFlags.h38
-rw-r--r--tools/flags/SkCommonFlags.cpp10
-rw-r--r--tools/flags/SkCommonFlags.h2
-rw-r--r--tools/flags/SkCommonFlagsConfig.cpp332
-rw-r--r--tools/flags/SkCommonFlagsConfig.h70
27 files changed, 1054 insertions, 203 deletions
diff --git a/bench/nanobench.cpp b/bench/nanobench.cpp
index 11119be2e1..638477ecf6 100644
--- a/bench/nanobench.cpp
+++ b/bench/nanobench.cpp
@@ -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();
}
diff --git a/dm/DM.cpp b/dm/DM.cpp
index c7e0934008..2351366fef 100644
--- 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);
}
}
diff --git a/dm/DMGpuSupport.h b/dm/DMGpuSupport.h
index 627dc4fda3..2cfdbdcc2c 100644
--- a/dm/DMGpuSupport.h
+++ b/dm/DMGpuSupport.h
@@ -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) {
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index e27628ad04..5bc5e5a30d 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -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.";
}
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 6b644ecdf3..5e053b1155 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -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;
diff --git a/gyp/flags.gyp b/gyp/flags.gyp
index 0fd52b375b..769a7bdb57 100644
--- a/gyp/flags.gyp
+++ b/gyp/flags.gyp
@@ -29,9 +29,15 @@
{
'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',
],
}
diff --git a/include/core/SkString.h b/include/core/SkString.h
index 9229d808a6..93514f2659 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -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
diff --git a/include/gpu/gl/SkNullGLContext.h b/include/gpu/gl/SkNullGLContext.h
index 1f63438264..9e799a9fea 100644
--- a/include/gpu/gl/SkNullGLContext.h
+++ b/include/gpu/gl/SkNullGLContext.h
@@ -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;
diff --git a/include/gpu/gl/angle/SkANGLEGLContext.h b/include/gpu/gl/angle/SkANGLEGLContext.h
index 7858fff964..ea5e877ca2 100644
--- a/include/gpu/gl/angle/SkANGLEGLContext.h
+++ b/include/gpu/gl/angle/SkANGLEGLContext.h
@@ -15,18 +15,25 @@
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;
diff --git a/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h b/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h
index 7fece3c83c..47f3fd967a 100644
--- a/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h
+++ b/include/gpu/gl/command_buffer/SkCommandBufferGLContext.h
@@ -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;
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index d93f662da3..b5655e0503 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -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
diff --git a/src/gpu/GrContextFactory.cpp b/src/gpu/GrContextFactory.cpp
index 15af8162b1..4814e7870e 100755
--- a/src/gpu/GrContextFactory.cpp
+++ b/src/gpu/GrContextFactory.cpp
@@ -24,13 +24,10 @@
#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()) {
diff --git a/src/gpu/GrContextFactory.h b/src/gpu/GrContextFactory.h
index 5097813817..1df99d6ff1 100644
--- a/src/gpu/GrContextFactory.h
+++ b/src/gpu/GrContextFactory.h
@@ -24,19 +24,23 @@
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;
diff --git a/src/gpu/gl/SkNullGLContext.cpp b/src/gpu/gl/SkNullGLContext.cpp
index e7270c32c4..dafa1ef0bc 100644
--- a/src/gpu/gl/SkNullGLContext.cpp
+++ b/src/gpu/gl/SkNullGLContext.cpp
@@ -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;
diff --git a/src/gpu/gl/angle/SkANGLEGLContext.cpp b/src/gpu/gl/angle/SkANGLEGLContext.cpp
index 54ef02d492..2c9f38e1d9 100644
--- a/src/gpu/gl/angle/SkANGLEGLContext.cpp
+++ b/src/gpu/gl/angle/SkANGLEGLContext.cpp
@@ -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();
}
diff --git a/src/gpu/gl/debug/SkDebugGLContext.h b/src/gpu/gl/debug/SkDebugGLContext.h
index abbcf559c5..113a254e0b 100644
--- a/src/gpu/gl/debug/SkDebugGLContext.h
+++ b/src/gpu/gl/debug/SkDebugGLContext.h
@@ -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:
diff --git a/src/gpu/gl/mesa/SkMesaGLContext.h b/src/gpu/gl/mesa/SkMesaGLContext.h
index a58f1c890e..a9c77a81da 100644
--- a/src/gpu/gl/mesa/SkMesaGLContext.h
+++ b/src/gpu/gl/mesa/SkMesaGLContext.h
@@ -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;
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 9fa8dafda6..065abf662b 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -435,18 +435,22 @@ 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));
}
}
diff --git a/tests/GrContextFactoryTest.cpp b/tests/GrContextFactoryTest.cpp
index 50bdedff9e..1b19ac68e3 100644
--- a/tests/GrContextFactoryTest.cpp
+++ b/tests/GrContextFactoryTest.cpp
@@ -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());
diff --git a/tests/StringTest.cpp b/tests/StringTest.cpp
index f621dc96af..9e41c48c84 100644
--- a/tests/StringTest.cpp
+++ b/tests/StringTest.cpp
@@ -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
index 0000000000..825615efc3
--- /dev/null
+++ b/tests/TestConfigParsing.cpp
@@ -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
+}
diff --git a/tools/flags/SkCommandLineFlags.cpp b/tools/flags/SkCommandLineFlags.cpp
index 9b2c9616cb..cddf9fb0b3 100644
--- a/tools/flags/SkCommandLineFlags.cpp
+++ b/tools/flags/SkCommandLineFlags.cpp
@@ -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;
}
diff --git a/tools/flags/SkCommandLineFlags.h b/tools/flags/SkCommandLineFlags.h
index 5909413523..909718d3e7 100644
--- a/tools/flags/SkCommandLineFlags.h
+++ b/tools/flags/SkCommandLineFlags.h
@@ -76,6 +76,11 @@
* 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;
diff --git a/tools/flags/SkCommonFlags.cpp b/tools/flags/SkCommonFlags.cpp
index 9783dde373..a2da1314fc 100644
--- a/tools/flags/SkCommonFlags.cpp
+++ b/tools/flags/SkCommonFlags.cpp
@@ -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,
diff --git a/tools/flags/SkCommonFlags.h b/tools/flags/SkCommonFlags.h
index d6fb2c1d9b..ddd8d3a4a2 100644
--- a/tools/flags/SkCommonFlags.h
+++ b/tools/flags/SkCommonFlags.h
@@ -10,11 +10,9 @@
#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
index 0000000000..82ac49340e
--- /dev/null
+++ b/tools/flags/SkCommonFlagsConfig.cpp
@@ -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
index 0000000000..54a076900e
--- /dev/null
+++ b/tools/flags/SkCommonFlagsConfig.h
@@ -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