aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD.gn1
-rw-r--r--gyp/utils.gypi2
-rw-r--r--include/utils/SkRTConf.h193
-rw-r--r--site/dev/runtime/config.md89
-rw-r--r--site/dev/runtime/index.md181
-rw-r--r--src/core/SkGraphics.cpp10
-rw-r--r--src/effects/SkBlurMaskFilter.cpp9
-rw-r--r--src/gpu/batches/GrAADistanceFieldPathRenderer.cpp1
-rw-r--r--src/gpu/gl/GrGLGpuProgramCache.cpp5
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp1
-rw-r--r--src/gpu/gl/builders/GrGLShaderStringBuilder.cpp5
-rw-r--r--src/gpu/vk/GrVkPipelineStateCache.cpp1
-rw-r--r--src/images/SkJPEGImageEncoder.cpp1
-rw-r--r--src/images/SkPNGImageEncoder.cpp9
-rw-r--r--src/opts/opts_check_x86.cpp1
-rw-r--r--src/utils/SkRTConf.cpp325
-rw-r--r--tests/PathOpsExtendedTest.cpp5
-rw-r--r--tests/PathOpsSkpClipTest.cpp14
-rw-r--r--tests/RTConfRegistryTest.cpp25
-rw-r--r--tests/RuntimeConfigTest.cpp28
-rw-r--r--tests/SkpSkGrTest.cpp1
21 files changed, 894 insertions, 13 deletions
diff --git a/BUILD.gn b/BUILD.gn
index 5a1ee01464..0d15f3169c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -461,6 +461,7 @@ test_lib("tests") {
sources = tests_sources - [
rebase_path("tests/FontMgrAndroidParserTest.cpp"), # Android only
rebase_path("tests/PathOpsSkpClipTest.cpp"), # alternate main
+ rebase_path("tests/RTConfRegistryTest.cpp"), # TODO: delete
rebase_path("tests/SkSLErrorTest.cpp"), # TODO: make work
rebase_path("tests/SkSLGLSLTest.cpp"), # TODO: make work
rebase_path("tests/SkpSkGrTest.cpp"), # doesn't compile
diff --git a/gyp/utils.gypi b/gyp/utils.gypi
index 4903f3d0fa..ac14a74ecd 100644
--- a/gyp/utils.gypi
+++ b/gyp/utils.gypi
@@ -28,6 +28,7 @@
'<(skia_include_path)/utils/SkParsePath.h',
'<(skia_include_path)/utils/SkPictureUtils.h',
'<(skia_include_path)/utils/SkRandom.h',
+ '<(skia_include_path)/utils/SkRTConf.h',
'<(skia_include_path)/utils/SkTextBox.h',
'<(skia_src_path)/utils/SkBase64.cpp',
@@ -67,6 +68,7 @@
'<(skia_src_path)/utils/SkPatchUtils.h',
'<(skia_src_path)/utils/SkRGBAToYUV.cpp',
'<(skia_src_path)/utils/SkRGBAToYUV.h',
+ '<(skia_src_path)/utils/SkRTConf.cpp',
'<(skia_src_path)/utils/SkTextBox.cpp',
'<(skia_src_path)/utils/SkTextureCompressor.cpp',
'<(skia_src_path)/utils/SkTextureCompressor.h',
diff --git a/include/utils/SkRTConf.h b/include/utils/SkRTConf.h
new file mode 100644
index 0000000000..d80e418419
--- /dev/null
+++ b/include/utils/SkRTConf.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2013 Google, Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkRTConf_DEFINED
+#define SkRTConf_DEFINED
+
+#include "../private/SkTDArray.h"
+#include "../private/SkTDict.h"
+#include "SkString.h"
+#include "SkStream.h"
+
+/** \class SkRTConfBase
+ Non-templated base class for the runtime configs
+*/
+
+class SkRTConfBase {
+public:
+ SkRTConfBase(const char *name) : fName(name) {}
+ virtual ~SkRTConfBase() {}
+ virtual const char *getName() const { return fName.c_str(); }
+ virtual bool isDefault() const = 0;
+ virtual void print(SkWStream *o) const = 0;
+ virtual bool equals(const SkRTConfBase *conf) const = 0;
+protected:
+ SkString fName;
+};
+
+/** \class SkRTConf
+ A class to provide runtime configurability.
+*/
+template<typename T> class SkRTConf: public SkRTConfBase {
+public:
+ SkRTConf(const char *name, const T &defaultValue, const char *description);
+ operator const T&() const { return fValue; }
+ void print(SkWStream *o) const;
+ bool equals(const SkRTConfBase *conf) const;
+ bool isDefault() const { return fDefault == fValue; }
+ void set(const T& value) { fValue = value; }
+protected:
+ void doPrint(char *s) const;
+
+ T fValue;
+ T fDefault;
+ SkString fDescription;
+};
+
+#ifdef SK_DEBUG
+#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf<confType> varName(confName, defaultValue, description)
+#define SK_CONF_SET(confname, value) \
+ skRTConfRegistry().set(confname, value, true)
+/* SK_CONF_TRY_SET() is like SK_CONF_SET(), but doesn't complain if
+ confname can't be found. This is useful if the SK_CONF_DECLARE is
+ inside a source file whose linkage is dependent on the system. */
+#define SK_CONF_TRY_SET(confname, value) \
+ skRTConfRegistry().set(confname, value, false)
+#else
+#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static confType varName = defaultValue
+#define SK_CONF_SET(confname, value) (void) confname, (void) value
+#define SK_CONF_TRY_SET(confname, value) (void) confname, (void) value
+#endif
+
+/** \class SkRTConfRegistry
+ A class that maintains a systemwide registry of all runtime configuration
+ parameters. Mainly used for printing them out and handling multiply-defined
+ knobs.
+*/
+
+class SkRTConfRegistry {
+public:
+ SkRTConfRegistry();
+ ~SkRTConfRegistry();
+ void printAll(const char *fname = NULL) const;
+ bool hasNonDefault() const;
+ void printNonDefault(const char *fname = NULL) const;
+ const char *configFileLocation() const;
+ void possiblyDumpFile() const;
+ void validate() const;
+ template <typename T> void set(const char *confname,
+ T value,
+ bool warnIfNotFound = true);
+
+private:
+ template<typename T> friend class SkRTConf;
+
+ void registerConf(SkRTConfBase *conf);
+
+ template <typename T> bool parse(const char *name, T* value);
+
+ SkTDArray<SkString *> fConfigFileKeys, fConfigFileValues;
+ typedef SkTDict< SkTDArray<SkRTConfBase *> * > ConfMap;
+ ConfMap fConfs;
+
+ template <typename T>
+ friend bool test_rt_conf_parse(SkRTConfRegistry*, const char* name, T* value);
+};
+
+// our singleton registry
+
+SkRTConfRegistry &skRTConfRegistry();
+
+template<typename T>
+SkRTConf<T>::SkRTConf(const char *name, const T &defaultValue, const char *description)
+ : SkRTConfBase(name)
+ , fValue(defaultValue)
+ , fDefault(defaultValue)
+ , fDescription(description) {
+
+ T value;
+ if (skRTConfRegistry().parse(fName.c_str(), &value)) {
+ fValue = value;
+ }
+ skRTConfRegistry().registerConf(this);
+}
+
+template<typename T>
+void SkRTConf<T>::print(SkWStream *o) const {
+ char outline[200]; // should be ok because we specify a max. width for everything here.
+ char *outptr;
+ if (strlen(getName()) >= 30) {
+ o->writeText(getName());
+ o->writeText(" ");
+ outptr = &(outline[0]);
+ } else {
+ sprintf(outline, "%-30.30s", getName());
+ outptr = &(outline[30]);
+ }
+
+ doPrint(outptr);
+ sprintf(outptr+30, " %.128s", fDescription.c_str());
+ for (size_t i = strlen(outline); i --> 0 && ' ' == outline[i];) {
+ outline[i] = '\0';
+ }
+ o->writeText(outline);
+}
+
+template<typename T>
+void SkRTConf<T>::doPrint(char *s) const {
+ sprintf(s, "%-30.30s", "How do I print myself??");
+}
+
+template<> inline void SkRTConf<bool>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false");
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> inline void SkRTConf<int>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%d # [%d]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> inline void SkRTConf<unsigned int>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%u # [%u]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> inline void SkRTConf<float>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> inline void SkRTConf<double>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<> inline void SkRTConf<const char *>::doPrint(char *s) const {
+ char tmp[30];
+ sprintf(tmp, "%s # [%s]", fValue, fDefault);
+ sprintf(s, "%-30.30s", tmp);
+}
+
+template<typename T>
+bool SkRTConf<T>::equals(const SkRTConfBase *conf) const {
+ // static_cast here is okay because there's only one kind of child class.
+ const SkRTConf<T> *child_pointer = static_cast<const SkRTConf<T> *>(conf);
+ return child_pointer &&
+ fName == child_pointer->fName &&
+ fDescription == child_pointer->fDescription &&
+ fValue == child_pointer->fValue &&
+ fDefault == child_pointer->fDefault;
+}
+
+#endif
diff --git a/site/dev/runtime/config.md b/site/dev/runtime/config.md
new file mode 100644
index 0000000000..fd31af75c5
--- /dev/null
+++ b/site/dev/runtime/config.md
@@ -0,0 +1,89 @@
+Runtime Configuration Settings
+==============================
+
+Here is a (partial) list of Skia's runtime configuration settings:
+
+## Warning suppression:
+
+* configuration name: images.gif.suppressDecoderWarnings
+ environment variable: skia_images_gif_suppressDecoderWarnings
+ type: boolean
+ description: Suppress GIF warnings and errors when calling image decode
+ functions.
+ default: true.
+
+* configuration name: images.jpeg.suppressDecoderWarnings
+ environment variable: skia_images_jpeg_suppressDecoderWarnings
+ type: boolean
+ description: Suppress most JPG warnings when calling decode functions.
+ default: false in debug, true otherwise.
+
+* configuration name: images.jpeg.suppressDecoderErrors
+ environment variable: skia_images_jpeg_suppressDecoderErrors
+ type: boolean
+ description: Suppress most JPG error messages when decode function fails.
+ default: false in debug, true otherwise.
+
+* configuration name: images.png.suppressDecoderWarnings
+ environment variable: skia_images_png_suppressDecoderWarnings
+ type: boolean
+ description: Suppress most PNG warnings when calling image decode functions.
+ default: false in debug, true otherwise.
+
+## Other:
+
+* configuration name: bitmap.filter
+ environment variable: skia_bitmap_filter
+ type: string
+ description: Which scanline bitmap filter to use \[mitchell, lanczos, hamming,
+ gaussian, triangle, box\]
+ default: mitchell
+
+* configuration name: mask.filter.analyticNinePatch
+ environment variable: skia_mask_filter_analyticNinePatch
+ type: boolean
+ description: Use the faster analytic blur approach for ninepatch rects
+ default: \?
+
+* configuration name: gpu.deferContext
+ environment variable: skia_gpu_deferContext
+ type: boolean
+ description: Defers rendering in GrContext via GrInOrderDrawBuffer
+ default: true
+
+* configuration name: gpu.dumpFontCache
+ environment variable: skia_gpu_dumpFontCache
+ type: boolean
+ description: Dump the contents of the font cache before every purge
+ default: false
+
+* configuration name: bitmap.filter.highQualitySSE
+ environment variable: skia_bitmap_filter_highQualitySSE
+ type: boolean
+ description: Use SSE optimized version of high quality image filters
+ default: false
+
+## Use:
+
+These configuration values can be changed at runtime by including this in your
+program:
+
+<!--?prettify?-->
+~~~~
+#include "SkRTConf.h"
+/*...*/
+int main() {
+ SK_CONF_SET( configuration_name, new_value );
+ /*...*/
+~~~~
+
+Or by setting the corresponding environment variable before starting the
+program. For example, in Bourne shell:
+
+<!--?prettify?-->
+~~~~
+#!/bin/sh
+export skia_environment_variable="new_value"
+your_program
+~~~~
+
diff --git a/site/dev/runtime/index.md b/site/dev/runtime/index.md
new file mode 100644
index 0000000000..7c8246d23f
--- /dev/null
+++ b/site/dev/runtime/index.md
@@ -0,0 +1,181 @@
+Runtime Configuration
+=====================
+
+Skia supports the configuration of various aspects of its behavior at runtime,
+allowing developers to enable\/disable features, or to experiment with numerical
+quantities without recompiling.
+
+## Enabling runtime configuration
+
+In order to use a runtime-configurable variable in your source, simply:
+
+<!--?prettify?-->
+~~~~
+#include "SkRTConf.h"
+~~~~
+
+## Declaring a runtime-configurable variable
+
+At file scope, declare your variable like so:
+
+<!--?prettify?-->
+~~~~
+SK_CONF_DECLARE( confType, varName, confName, defaultValue, description );
+~~~~
+
+For example, to declare a boolean variable called ` c_printShaders ` that can be
+changed at runtime, you would do something like
+
+<!--?prettify?-->
+~~~~
+SK_CONF_DECLARE( bool, c_printShaders, "gpu.printShaders", false, "print the
+ source code of any internally generated GPU shaders" );
+~~~~
+
+It is safe to declare variables this way in header files; the variables will be
+declared as static, but since they are read\-only\-ish \(they can be changed
+through a special mechanism; see below\), this is safe.
+
+## Using a runtime-configurable variable
+
+The variables created by `SK_CONF_DECLARE` can be used in normal C\+\+ code as
+if they were regular contant variables. For example:
+
+<!--?prettify?-->
+~~~~
+if (c_printShaders) {
+ // actually print out the shaders
+}
+~~~~
+
+## Changing a runtime-configurable variable after launch
+
+If, for some reason, you want to change the value of a runtime-configurable
+variable after your program has started, you can do this with the `SK_CONF_SET`
+macro:
+
+<!--?prettify?-->
+~~~~
+SK_CONF_SET( "gpu.printShaders", false )
+~~~~
+
+Note that we're using the `confName` parameter to the declaration, not
+`varName`. This is because this configuration option may appear in multiple
+files \(especially if you declared it in a header!\), and we need to make sure
+to update all variables' values, not just the one that's locally visible to the
+file you are currently in.
+
+## Changing a runtime-configurable variable before launch
+
+This is the primary intended use of these variables. There are two ways that you
+can control the values of runtime-configurable variables at launch time: a
+skia.conf configuration file, or through the use of environment variables.
+
+### Using skia.conf
+
+The skia.conf file is a simple line-based configuration file containing
+key-value pairs. It supports python-style \# comments. For our example, we might
+see a configuration file that looks like:
+
+<!--?prettify?-->
+~~~~
+gpu.printShaders true
+gpu.somethingElse 3.14159
+matrix.invertProperly false # math is hard
+...
+~~~~
+
+*Note: boolean values may be set as 1, 0, true, or false. Other values will
+result in runtime errors.*
+
+If the skia library detects a skia.conf file at initialization time, it will
+parse it and override the default values of any declared configuration variables
+with the values found in the file.
+
+*Note: although it might appear that the configuration variables have a
+hierarchical naming scheme involving periods, that's just a convention I have
+adopted so that when all declared configuration variables are sorted
+alphabetically, they are roughly grouped by component.*
+
+## Using environment variables
+
+You can quickly override the value of one runtime-configurable variable using an
+environment variable equal to the variable's key with "skia." prepended. So, for
+example, one might run:
+
+<!--?prettify?-->
+~~~~
+prompt% skia.gpu.printShaders=true out/Debug/dm
+~~~~
+
+or
+
+<!--?prettify?-->
+~~~~
+prompt% export skia.gpu.printShaders=true
+prompt% out/Debug/dm
+~~~~
+
+On many shells, it is illegal to have a period in an environment variable name,
+so skia also supports underscores in place of the periods:
+
+<!--?prettify?-->
+~~~~
+prompt% skia_gpu_printShaders=true out/Debug/dm
+~~~~
+
+or
+
+<!--?prettify?-->
+~~~~
+prompt% export skia_gpu_printShaders=true`
+prompt% out/Debug/dm
+~~~~
+
+## Discovering all possible configuration variables
+
+As this system becomes more widely used in skia, there may be hundreds of
+configuration variables. What are they all? What are their defaults? What do
+they do?
+
+In order to find out, simply create a zero-length skia.conf file \(on unix,
+`touch skia.conf` will do the trick\). If skia detects a zero-length
+configuration file, it will overwrite it with a sorted list of all known
+configuration variables, their defaults, and their description strings. Each
+line will be commented out and have its value already equal to its default, so
+you can then edit this file to your liking.
+
+To trigger this behavior, call the function
+`skRTConfRegistry().possiblyDumpFile(); ` or simply use `SkAutoGraphics
+ag;`, which also validates your configuration and print out active non-default
+options.
+
+## Are these things enabled all the time?
+
+No, they are only enabled in builds where SK_DEBUG is defined. This includes both
+`Debug` and `Release_Developer` gyp BUILDTYPES. The `Release_Developer` build type
+has exactly the same build flags as `Release`, except it re-enables SK_DEBUG, which
+in turn enables runtime configuration behavior.
+Specifically:
+
+<!--?prettify?-->
+~~~~
+prompt% ninja -C BUILDTYPE=Release_Developer
+~~~~
+
+... wait a long time ...
+
+<!--?prettify?-->
+~~~~
+prompt % skia_gpu_printShaders=true out/Release_Developer/dm
+~~~~
+
+... enjoy ...
+
+## Known issues / limitations
+
+Lines in 'skia.conf', including comments, are limited to 1024 characters.
+Runtime configuration variables of type `char \* ` cannot currently have spaces
+in them.
+Runtime variables are only fully supported for `int`, `unsigned int`, `float`,
+`double`, `bool`, and `char \*`.
diff --git a/src/core/SkGraphics.cpp b/src/core/SkGraphics.cpp
index 01b1432ef0..d7022b770b 100644
--- a/src/core/SkGraphics.cpp
+++ b/src/core/SkGraphics.cpp
@@ -22,6 +22,7 @@
#include "SkPixelRef.h"
#include "SkRefCnt.h"
#include "SkResourceCache.h"
+#include "SkRTConf.h"
#include "SkScalerContext.h"
#include "SkShader.h"
#include "SkStream.h"
@@ -48,6 +49,15 @@ void SkGraphics::Init() {
// SkGraphics::Init() must be thread-safe and idempotent.
SkCpu::CacheRuntimeFeatures();
SkOpts::Init();
+
+#ifdef SK_DEBUG
+ skRTConfRegistry().possiblyDumpFile();
+ skRTConfRegistry().validate();
+ if (skRTConfRegistry().hasNonDefault()) {
+ SkDebugf("Non-default runtime configuration options:\n");
+ skRTConfRegistry().printNonDefault();
+ }
+#endif
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 38b5313be3..9e0315f2b7 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -12,6 +12,7 @@
#include "SkWriteBuffer.h"
#include "SkMaskFilter.h"
#include "SkRRect.h"
+#include "SkRTConf.h"
#include "SkStringUtils.h"
#include "SkStrokeRec.h"
@@ -303,10 +304,9 @@ static SkCachedData* add_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle
}
#ifdef SK_IGNORE_FAST_RRECT_BLUR
- // Use the faster analytic blur approach for ninepatch round rects
- static const bool c_analyticBlurRRect{false};
+SK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects");
#else
- static const bool c_analyticBlurRRect{true};
+SK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", true, "Use the faster analytic blur approach for ninepatch round rects");
#endif
SkMaskFilter::FilterReturn
@@ -443,8 +443,7 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma
return kTrue_FilterReturn;
}
-// Use the faster analytic blur approach for ninepatch rects
-static const bool c_analyticBlurNinepatch{true};
+SK_CONF_DECLARE(bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects");
SkMaskFilter::FilterReturn
SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index 36a9ff01e7..a9ba94da40 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -20,6 +20,7 @@
#include "effects/GrDistanceFieldGeoProc.h"
#include "SkDistanceFieldGen.h"
+#include "SkRTConf.h"
#define ATLAS_TEXTURE_WIDTH 2048
#define ATLAS_TEXTURE_HEIGHT 2048
diff --git a/src/gpu/gl/GrGLGpuProgramCache.cpp b/src/gpu/gl/GrGLGpuProgramCache.cpp
index ae93926c79..4ba0d23ae5 100644
--- a/src/gpu/gl/GrGLGpuProgramCache.cpp
+++ b/src/gpu/gl/GrGLGpuProgramCache.cpp
@@ -13,11 +13,12 @@
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLProgramDesc.h"
+#include "SkRTConf.h"
#include "SkTSearch.h"
#ifdef PROGRAM_CACHE_STATS
-// Display program cache usage
-static const bool c_DisplayCache{false};
+SK_CONF_DECLARE(bool, c_DisplayCache, "gpu.displayCache", false,
+ "Display program cache usage.");
#endif
typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 2bbeb42af6..2d06e434f2 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -12,6 +12,7 @@
#include "GrGLProgramBuilder.h"
#include "GrSwizzle.h"
#include "GrTexture.h"
+#include "SkRTConf.h"
#include "SkTraceEvent.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLProgram.h"
diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
index 296c2beb44..b4ce2824e2 100644
--- a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
@@ -8,13 +8,14 @@
#include "GrGLShaderStringBuilder.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLSLPrettyPrint.h"
+#include "SkRTConf.h"
#include "SkTraceEvent.h"
#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
-// Print the source code for all shaders generated.
-static const bool c_PrintShaders{false};
+SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
+ "Print the source code for all shaders generated.");
static void print_shader_source(const char** strings, int* lengths, int count);
diff --git a/src/gpu/vk/GrVkPipelineStateCache.cpp b/src/gpu/vk/GrVkPipelineStateCache.cpp
index 494f659e9f..b8335e8e44 100644
--- a/src/gpu/vk/GrVkPipelineStateCache.cpp
+++ b/src/gpu/vk/GrVkPipelineStateCache.cpp
@@ -11,6 +11,7 @@
#include "GrProcessor.h"
#include "GrVkPipelineState.h"
#include "GrVkPipelineStateBuilder.h"
+#include "SkRTConf.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLProgramDataManager.h"
diff --git a/src/images/SkJPEGImageEncoder.cpp b/src/images/SkJPEGImageEncoder.cpp
index 66b2440c20..1051aec205 100644
--- a/src/images/SkJPEGImageEncoder.cpp
+++ b/src/images/SkJPEGImageEncoder.cpp
@@ -13,6 +13,7 @@
#include "SkTemplates.h"
#include "SkTime.h"
#include "SkUtils.h"
+#include "SkRTConf.h"
#include "SkRect.h"
#include "SkCanvas.h"
diff --git a/src/images/SkPNGImageEncoder.cpp b/src/images/SkPNGImageEncoder.cpp
index 1932e66dc6..c3df5d10a8 100644
--- a/src/images/SkPNGImageEncoder.cpp
+++ b/src/images/SkPNGImageEncoder.cpp
@@ -10,6 +10,7 @@
#include "SkColorPriv.h"
#include "SkDither.h"
#include "SkMath.h"
+#include "SkRTConf.h"
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
@@ -35,9 +36,11 @@
#endif
#define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS true
-// Suppress most PNG warnings when calling image decode functions.
-static const bool c_suppressPNGImageDecoderWarnings{
- DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS};
+SK_CONF_DECLARE(bool, c_suppressPNGImageDecoderWarnings,
+ "images.png.suppressDecoderWarnings",
+ DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS,
+ "Suppress most PNG warnings when calling image decode "
+ "functions.");
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/opts/opts_check_x86.cpp b/src/opts/opts_check_x86.cpp
index a8003a3b0e..dacb49bc91 100644
--- a/src/opts/opts_check_x86.cpp
+++ b/src/opts/opts_check_x86.cpp
@@ -13,6 +13,7 @@
#include "SkBlitRow.h"
#include "SkBlitRow_opts_SSE2.h"
#include "SkCpu.h"
+#include "SkRTConf.h"
/*
diff --git a/src/utils/SkRTConf.cpp b/src/utils/SkRTConf.cpp
new file mode 100644
index 0000000000..2dfa47efc7
--- /dev/null
+++ b/src/utils/SkRTConf.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRTConf.h"
+#include "SkOSFile.h"
+
+#include <stdlib.h>
+
+SkRTConfRegistry::SkRTConfRegistry(): fConfs(100) {
+
+ FILE *fp = sk_fopen(configFileLocation(), kRead_SkFILE_Flag);
+
+ if (!fp) {
+ return;
+ }
+
+ char line[1024];
+
+ while (!sk_feof(fp)) {
+
+ if (!sk_fgets(line, sizeof(line), fp)) {
+ break;
+ }
+
+ char *commentptr = strchr(line, '#');
+ if (commentptr == line) {
+ continue;
+ }
+ if (commentptr) {
+ *commentptr = '\0';
+ }
+
+ char sep[] = " \t\r\n";
+
+ char *keyptr = strtok(line, sep);
+ if (!keyptr) {
+ continue;
+ }
+
+ char *valptr = strtok(nullptr, sep);
+ if (!valptr) {
+ continue;
+ }
+
+ SkString *key = new SkString(keyptr);
+ SkString *val = new SkString(valptr);
+
+ fConfigFileKeys.append(1, &key);
+ fConfigFileValues.append(1, &val);
+ }
+ sk_fclose(fp);
+}
+
+SkRTConfRegistry::~SkRTConfRegistry() {
+ ConfMap::Iter iter(fConfs);
+ SkTDArray<SkRTConfBase *> *confArray;
+
+ while (iter.next(&confArray)) {
+ delete confArray;
+ }
+
+ for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
+ delete fConfigFileKeys[i];
+ delete fConfigFileValues[i];
+ }
+}
+
+const char *SkRTConfRegistry::configFileLocation() const {
+ return "skia.conf"; // for now -- should probably do something fancier like home directories or whatever.
+}
+
+// dump all known runtime config options to the file with their default values.
+// to trigger this, make a config file of zero size.
+void SkRTConfRegistry::possiblyDumpFile() const {
+ const char *path = configFileLocation();
+ FILE *fp = sk_fopen(path, kRead_SkFILE_Flag);
+ if (!fp) {
+ return;
+ }
+ size_t configFileSize = sk_fgetsize(fp);
+ if (configFileSize == 0) {
+ printAll(path);
+ }
+ sk_fclose(fp);
+}
+
+// Run through every provided configuration option and print a warning if the user hasn't
+// declared a correponding configuration object somewhere.
+void SkRTConfRegistry::validate() const {
+ for (int i = 0 ; i < fConfigFileKeys.count() ; i++) {
+ if (!fConfs.find(fConfigFileKeys[i]->c_str())) {
+ SkDebugf("WARNING: You have config value %s in your configuration file, but I've never heard of that.\n", fConfigFileKeys[i]->c_str());
+ }
+ }
+}
+
+void SkRTConfRegistry::printAll(const char *fname) const {
+ SkWStream *o;
+
+ if (fname) {
+ o = new SkFILEWStream(fname);
+ } else {
+ o = new SkDebugWStream();
+ }
+
+ ConfMap::Iter iter(fConfs);
+ SkTDArray<SkRTConfBase *> *confArray;
+
+ while (iter.next(&confArray)) {
+ if (confArray->getAt(0)->isDefault()) {
+ o->writeText("# ");
+ }
+ confArray->getAt(0)->print(o);
+ o->newline();
+ }
+
+ delete o;
+}
+
+bool SkRTConfRegistry::hasNonDefault() const {
+ ConfMap::Iter iter(fConfs);
+ SkTDArray<SkRTConfBase *> *confArray;
+ while (iter.next(&confArray)) {
+ if (!confArray->getAt(0)->isDefault()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SkRTConfRegistry::printNonDefault(const char *fname) const {
+ SkWStream *o;
+
+ if (fname) {
+ o = new SkFILEWStream(fname);
+ } else {
+ o = new SkDebugWStream();
+ }
+ ConfMap::Iter iter(fConfs);
+ SkTDArray<SkRTConfBase *> *confArray;
+
+ while (iter.next(&confArray)) {
+ if (!confArray->getAt(0)->isDefault()) {
+ confArray->getAt(0)->print(o);
+ o->newline();
+ }
+ }
+
+ delete o;
+}
+
+// register a configuration variable after its value has been set by the parser.
+// we maintain a vector of these things instead of just a single one because the
+// user might set the value after initialization time and we need to have
+// all the pointers lying around, not just one.
+void SkRTConfRegistry::registerConf(SkRTConfBase *conf) {
+ SkTDArray<SkRTConfBase *> *confArray;
+ if (fConfs.find(conf->getName(), &confArray)) {
+ if (!conf->equals(confArray->getAt(0))) {
+ SkDebugf("WARNING: Skia config \"%s\" was registered more than once in incompatible ways.\n", conf->getName());
+ } else {
+ confArray->append(1, &conf);
+ }
+ } else {
+ confArray = new SkTDArray<SkRTConfBase *>;
+ confArray->append(1, &conf);
+ fConfs.set(conf->getName(),confArray);
+ }
+}
+
+template <typename T> T doParse(const char *, bool *success ) {
+ SkDebugf("WARNING: Invoked non-specialized doParse function...\n");
+ if (success) {
+ *success = false;
+ }
+ return (T) 0;
+}
+
+template<> bool doParse<bool>(const char *s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ if (!strcmp(s,"1") || !strcmp(s,"true")) {
+ return true;
+ }
+ if (!strcmp(s,"0") || !strcmp(s,"false")) {
+ return false;
+ }
+ if (success) {
+ *success = false;
+ }
+ return false;
+}
+
+template<> const char * doParse<const char *>(const char * s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ return s;
+}
+
+template<> int doParse<int>(const char * s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ return atoi(s);
+}
+
+template<> unsigned int doParse<unsigned int>(const char * s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ return (unsigned int) atoi(s);
+}
+
+template<> float doParse<float>(const char * s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ return (float) atof(s);
+}
+
+template<> double doParse<double>(const char * s, bool *success) {
+ if (success) {
+ *success = true;
+ }
+ return atof(s);
+}
+
+static inline void str_replace(char *s, char search, char replace) {
+ for (char *ptr = s ; *ptr ; ptr++) {
+ if (*ptr == search) {
+ *ptr = replace;
+ }
+ }
+}
+
+template<typename T> bool SkRTConfRegistry::parse(const char *name, T* value) {
+ const char *str = nullptr;
+
+ for (int i = fConfigFileKeys.count() - 1 ; i >= 0; i--) {
+ if (fConfigFileKeys[i]->equals(name)) {
+ str = fConfigFileValues[i]->c_str();
+ break;
+ }
+ }
+
+ SkString environment_variable("skia.");
+ environment_variable.append(name);
+
+ const char *environment_value = getenv(environment_variable.c_str());
+ if (environment_value) {
+ str = environment_value;
+ } else {
+ // apparently my shell doesn't let me have environment variables that
+ // have periods in them, so also let the user substitute underscores.
+ SkAutoTMalloc<char> underscore_name(SkStrDup(environment_variable.c_str()));
+ str_replace(underscore_name.get(), '.', '_');
+ environment_value = getenv(underscore_name.get());
+ if (environment_value) {
+ str = environment_value;
+ }
+ }
+
+ if (!str) {
+ return false;
+ }
+
+ bool success;
+ T new_value = doParse<T>(str, &success);
+ if (success) {
+ *value = new_value;
+ } else {
+ SkDebugf("WARNING: Couldn't parse value \'%s\' for variable \'%s\'\n",
+ str, name);
+ }
+ return success;
+}
+
+// need to explicitly instantiate the parsing function for every config type we might have...
+
+template bool SkRTConfRegistry::parse(const char *name, bool *value);
+template bool SkRTConfRegistry::parse(const char *name, int *value);
+template bool SkRTConfRegistry::parse(const char *name, unsigned int *value);
+template bool SkRTConfRegistry::parse(const char *name, float *value);
+template bool SkRTConfRegistry::parse(const char *name, double *value);
+template bool SkRTConfRegistry::parse(const char *name, const char **value);
+
+template <typename T> void SkRTConfRegistry::set(const char *name,
+ T value,
+ bool warnIfNotFound) {
+ SkTDArray<SkRTConfBase *> *confArray;
+ if (!fConfs.find(name, &confArray)) {
+ if (warnIfNotFound) {
+ SkDebugf("WARNING: Attempting to set configuration value \"%s\","
+ " but I've never heard of that.\n", name);
+ }
+ return;
+ }
+ SkASSERT(confArray != nullptr);
+ for (SkRTConfBase **confBase = confArray->begin(); confBase != confArray->end(); confBase++) {
+ // static_cast here is okay because there's only one kind of child class.
+ SkRTConf<T> *concrete = static_cast<SkRTConf<T> *>(*confBase);
+
+ if (concrete) {
+ concrete->set(value);
+ }
+ }
+}
+
+template void SkRTConfRegistry::set(const char *name, bool value, bool);
+template void SkRTConfRegistry::set(const char *name, int value, bool);
+template void SkRTConfRegistry::set(const char *name, unsigned int value, bool);
+template void SkRTConfRegistry::set(const char *name, float value, bool);
+template void SkRTConfRegistry::set(const char *name, double value, bool);
+template void SkRTConfRegistry::set(const char *name, char * value, bool);
+
+SkRTConfRegistry &skRTConfRegistry() {
+ static SkRTConfRegistry r;
+ return r;
+}
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index 6ea67fe89f..2f6d99d652 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -13,6 +13,7 @@
#include "SkMatrix.h"
#include "SkMutex.h"
#include "SkPaint.h"
+#include "SkRTConf.h"
#include "SkStream.h"
#include <stdlib.h>
@@ -629,6 +630,10 @@ bool testPathOpFail(skiatest::Reporter* reporter, const SkPath& a, const SkPath&
SK_DECLARE_STATIC_MUTEX(gMutex);
void initializeTests(skiatest::Reporter* reporter, const char* test) {
+#if 0 // doesn't work yet
+ SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
+ SK_CONF_SET("images.png.suppressDecoderWarnings", true);
+#endif
if (reporter->verbose()) {
SkAutoMutexAcquire lock(gMutex);
testName = test;
diff --git a/tests/PathOpsSkpClipTest.cpp b/tests/PathOpsSkpClipTest.cpp
index 3c958f1bec..c96e5bf66c 100644
--- a/tests/PathOpsSkpClipTest.cpp
+++ b/tests/PathOpsSkpClipTest.cpp
@@ -19,6 +19,7 @@
#include "SkOSFile.h"
#include "SkPathOpsDebug.h"
#include "SkPicture.h"
+#include "SkRTConf.h"
#include "SkTSort.h"
#include "SkStream.h"
#include "SkString.h"
@@ -26,7 +27,6 @@
#include "SkTDArray.h"
#include "SkTaskGroup.h"
#include "SkTemplates.h"
-#include "SkTSearch.h"
#include "SkTime.h"
#include <stdlib.h>
@@ -740,6 +740,13 @@ checkEarlyExit:
return true;
}
+static void initTest() {
+#if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
+ SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
+ SK_CONF_SET("images.png.suppressDecoderWarnings", true);
+#endif
+}
+
static void testSkpClipEncode(TestState* data) {
data->fResult.testOne();
if (verbose()) {
@@ -820,6 +827,7 @@ typedef SkTRegistry<Test*(*)(void*)> TestRegistry;
DEF_TEST(PathOpsSkpClip) {
gDirs.setDefault();
+ initTest();
SkTArray<TestResult, true> errors;
TestState state;
state.init(0);
@@ -843,6 +851,7 @@ static void testSkpClipMain(TestState* data) {
DEF_TEST(PathOpsSkpClipThreaded) {
gDirs.setDefault();
+ initTest();
TestRunner testRunner;
int dirNo;
gDirs.reset();
@@ -881,6 +890,7 @@ DEF_TEST(PathOpsSkpClipUberThreaded) {
gDirs.setDefault();
const int firstDirNo = gDirs.next();
const int lastDirNo = gDirs.last();
+ initTest();
int dirCount = lastDirNo - firstDirNo + 1;
SkAutoTDeleteArray<SkTDArray<TestResult> > tests(new SkTDArray<TestResult>[dirCount]);
SkAutoTDeleteArray<SkTDArray<SortByName*> > sorted(new SkTDArray<SortByName*>[dirCount]);
@@ -963,6 +973,7 @@ DEF_TEST(PathOpsSkpClipOneOff) {
if (!skp) {
skp = skipOver[testIndex].filename;
}
+ initTest();
SkAssertResult(get_in_path(dirNo, skp).size());
SkString filename(skp);
TestResult state;
@@ -982,6 +993,7 @@ DEF_TEST(PathOpsTestSkipped) {
}
int dirNo = skip.directory;
const char* skp = skip.filename;
+ initTest();
SkAssertResult(get_in_path(dirNo, skp).size());
SkString filename(skp);
TestResult state;
diff --git a/tests/RTConfRegistryTest.cpp b/tests/RTConfRegistryTest.cpp
new file mode 100644
index 0000000000..be019f70b4
--- /dev/null
+++ b/tests/RTConfRegistryTest.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkRTConf.h"
+#include "SkOSEnvironment.h"
+#include "Test.h"
+
+// Friended proxy for SkRTConfRegistry::parse()
+template <typename T>
+bool test_rt_conf_parse(SkRTConfRegistry* reg, const char* key, T* value) {
+ return reg->parse(key, value);
+}
+
+DEF_TEST(SkRTConfRegistry, reporter) {
+ SkRTConfRegistry reg;
+
+ sk_setenv("skia_nonexistent_item", "132");
+ int result = 0;
+ test_rt_conf_parse(&reg, "nonexistent.item", &result);
+ REPORTER_ASSERT(reporter, result == 132);
+}
diff --git a/tests/RuntimeConfigTest.cpp b/tests/RuntimeConfigTest.cpp
new file mode 100644
index 0000000000..b863ee1fd8
--- /dev/null
+++ b/tests/RuntimeConfigTest.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkRTConf.h"
+#include "Test.h"
+
+SK_CONF_DECLARE(int, c_RTConfTestVariable,
+ "test.utils.rtconf.testVariable", 1,
+ "This is only a test. Do not be alarmed.");
+// TODO(skia-team): more comprehensive unit tests of the SkRTConf
+// system.
+DEF_TEST(RuntimeConfig, reporter) {
+ REPORTER_ASSERT(reporter, 1 == c_RTConfTestVariable);
+
+ SK_CONF_SET("test.utils.rtconf.testVariable", 2);
+#ifdef SK_DEBUG
+ REPORTER_ASSERT(reporter, 2 == c_RTConfTestVariable);
+#else // not SK_DEBUG
+ // Can not change RTConf variables in SK_RELEASE.
+ REPORTER_ASSERT(reporter, 1 == c_RTConfTestVariable);
+#endif // SK_DEBUG
+
+ // This should not give a warning.
+ SK_CONF_TRY_SET("test.utils.rtconf.nonexistentVariable", 7);
+}
diff --git a/tests/SkpSkGrTest.cpp b/tests/SkpSkGrTest.cpp
index ccec37bf21..bf534f4820 100644
--- a/tests/SkpSkGrTest.cpp
+++ b/tests/SkpSkGrTest.cpp
@@ -18,6 +18,7 @@
#include "SkImageEncoder.h"
#include "SkOSFile.h"
#include "SkPicture.h"
+#include "SkRTConf.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkTArray.h"