diff options
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(); } @@ -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 |