aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/effects/GrAlphaThresholdFragmentProcessor.cpp19
-rw-r--r--src/effects/GrAlphaThresholdFragmentProcessor.h2
-rw-r--r--src/effects/GrCircleBlurFragmentProcessor.cpp13
-rw-r--r--src/effects/GrCircleBlurFragmentProcessor.h2
-rw-r--r--src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp8
-rw-r--r--src/gpu/effects/GrBlurredEdgeFragmentProcessor.h2
-rw-r--r--src/gpu/effects/GrCircleEffect.cpp10
-rw-r--r--src/gpu/effects/GrCircleEffect.h2
-rw-r--r--src/gpu/effects/GrDitherEffect.cpp7
-rw-r--r--src/gpu/effects/GrDitherEffect.h2
-rw-r--r--src/gpu/effects/GrEllipseEffect.cpp10
-rw-r--r--src/gpu/effects/GrEllipseEffect.h2
-rw-r--r--src/gpu/effects/GrSimpleTextureEffect.cpp13
-rw-r--r--src/gpu/effects/GrSimpleTextureEffect.h2
-rw-r--r--src/sksl/README1
-rw-r--r--src/sksl/SkSLCPPCodeGenerator.cpp45
-rw-r--r--src/sksl/SkSLCPPCodeGenerator.h4
-rw-r--r--src/sksl/SkSLHCodeGenerator.cpp6
-rw-r--r--src/sksl/SkSLSectionAndParameterHelper.h2
-rw-r--r--tests/SkSLFPTest.cpp10
20 files changed, 158 insertions, 4 deletions
diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.cpp b/src/effects/GrAlphaThresholdFragmentProcessor.cpp
index fab78cea9d..731ca99d3b 100644
--- a/src/effects/GrAlphaThresholdFragmentProcessor.cpp
+++ b/src/effects/GrAlphaThresholdFragmentProcessor.cpp
@@ -107,6 +107,25 @@ bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& oth
if (fOuterThreshold != that.fOuterThreshold) return false;
return true;
}
+GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor(
+ const GrAlphaThresholdFragmentProcessor& src)
+ : INHERITED(src.optimizationFlags())
+ , fImage(src.fImage)
+ , fColorXform(src.fColorXform)
+ , fMask(src.fMask)
+ , fInnerThreshold(src.fInnerThreshold)
+ , fOuterThreshold(src.fOuterThreshold)
+ , fImageCoordTransform(src.fImageCoordTransform)
+ , fMaskCoordTransform(src.fMaskCoordTransform) {
+ this->initClassID<GrAlphaThresholdFragmentProcessor>();
+ this->addTextureSampler(&fImage);
+ this->addTextureSampler(&fMask);
+ this->addCoordTransform(&fImageCoordTransform);
+ this->addCoordTransform(&fMaskCoordTransform);
+}
+sk_sp<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(*this));
+}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor);
#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate(
diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.h b/src/effects/GrAlphaThresholdFragmentProcessor.h
index e2b10e8cb7..78424d0359 100644
--- a/src/effects/GrAlphaThresholdFragmentProcessor.h
+++ b/src/effects/GrAlphaThresholdFragmentProcessor.h
@@ -35,6 +35,8 @@ public:
return sk_sp<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(
image, colorXform, mask, innerThreshold, outerThreshold, bounds));
}
+ GrAlphaThresholdFragmentProcessor(const GrAlphaThresholdFragmentProcessor& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "AlphaThresholdFragmentProcessor"; }
private:
diff --git a/src/effects/GrCircleBlurFragmentProcessor.cpp b/src/effects/GrCircleBlurFragmentProcessor.cpp
index 1d281f045e..68ba0af0d4 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.cpp
+++ b/src/effects/GrCircleBlurFragmentProcessor.cpp
@@ -285,6 +285,19 @@ bool GrCircleBlurFragmentProcessor::onIsEqual(const GrFragmentProcessor& other)
if (fBlurProfileSampler != that.fBlurProfileSampler) return false;
return true;
}
+GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor(
+ const GrCircleBlurFragmentProcessor& src)
+ : INHERITED(src.optimizationFlags())
+ , fCircleRect(src.fCircleRect)
+ , fTextureRadius(src.fTextureRadius)
+ , fSolidRadius(src.fSolidRadius)
+ , fBlurProfileSampler(src.fBlurProfileSampler) {
+ this->initClassID<GrCircleBlurFragmentProcessor>();
+ this->addTextureSampler(&fBlurProfileSampler);
+}
+sk_sp<GrFragmentProcessor> GrCircleBlurFragmentProcessor::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(*this));
+}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor);
#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate(
diff --git a/src/effects/GrCircleBlurFragmentProcessor.h b/src/effects/GrCircleBlurFragmentProcessor.h
index 4a450d7a66..9ef204d403 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.h
+++ b/src/effects/GrCircleBlurFragmentProcessor.h
@@ -23,6 +23,8 @@ public:
static sk_sp<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
const SkRect& circle, float sigma);
+ GrCircleBlurFragmentProcessor(const GrCircleBlurFragmentProcessor& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "CircleBlurFragmentProcessor"; }
private:
diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
index f63422ffcd..8c0ff64d27 100644
--- a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
@@ -50,4 +50,12 @@ bool GrBlurredEdgeFragmentProcessor::onIsEqual(const GrFragmentProcessor& other)
if (fMode != that.fMode) return false;
return true;
}
+GrBlurredEdgeFragmentProcessor::GrBlurredEdgeFragmentProcessor(
+ const GrBlurredEdgeFragmentProcessor& src)
+ : INHERITED(src.optimizationFlags()), fMode(src.fMode) {
+ this->initClassID<GrBlurredEdgeFragmentProcessor>();
+}
+sk_sp<GrFragmentProcessor> GrBlurredEdgeFragmentProcessor::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrBlurredEdgeFragmentProcessor(*this));
+}
#endif
diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.h b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.h
index 733fd8342c..677c285114 100644
--- a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.h
+++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.h
@@ -22,6 +22,8 @@ public:
static sk_sp<GrFragmentProcessor> Make(int mode) {
return sk_sp<GrFragmentProcessor>(new GrBlurredEdgeFragmentProcessor(mode));
}
+ GrBlurredEdgeFragmentProcessor(const GrBlurredEdgeFragmentProcessor& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "BlurredEdgeFragmentProcessor"; }
private:
diff --git a/src/gpu/effects/GrCircleEffect.cpp b/src/gpu/effects/GrCircleEffect.cpp
index 97bfda4dbb..6fc47558c9 100644
--- a/src/gpu/effects/GrCircleEffect.cpp
+++ b/src/gpu/effects/GrCircleEffect.cpp
@@ -88,6 +88,16 @@ bool GrCircleEffect::onIsEqual(const GrFragmentProcessor& other) const {
if (fRadius != that.fRadius) return false;
return true;
}
+GrCircleEffect::GrCircleEffect(const GrCircleEffect& src)
+ : INHERITED(src.optimizationFlags())
+ , fEdgeType(src.fEdgeType)
+ , fCenter(src.fCenter)
+ , fRadius(src.fRadius) {
+ this->initClassID<GrCircleEffect>();
+}
+sk_sp<GrFragmentProcessor> GrCircleEffect::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrCircleEffect(*this));
+}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleEffect);
#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrCircleEffect::TestCreate(GrProcessorTestData* testData) {
diff --git a/src/gpu/effects/GrCircleEffect.h b/src/gpu/effects/GrCircleEffect.h
index fae8155389..46e46f9575 100644
--- a/src/gpu/effects/GrCircleEffect.h
+++ b/src/gpu/effects/GrCircleEffect.h
@@ -23,6 +23,8 @@ public:
static sk_sp<GrFragmentProcessor> Make(int edgeType, SkPoint center, float radius) {
return sk_sp<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius));
}
+ GrCircleEffect(const GrCircleEffect& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "CircleEffect"; }
private:
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index 38e4c77564..3b70493338 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -57,6 +57,13 @@ bool GrDitherEffect::onIsEqual(const GrFragmentProcessor& other) const {
if (fRangeType != that.fRangeType) return false;
return true;
}
+GrDitherEffect::GrDitherEffect(const GrDitherEffect& src)
+ : INHERITED(src.optimizationFlags()), fRangeType(src.fRangeType) {
+ this->initClassID<GrDitherEffect>();
+}
+sk_sp<GrFragmentProcessor> GrDitherEffect::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrDitherEffect(*this));
+}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDitherEffect);
#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrDitherEffect::TestCreate(GrProcessorTestData* testData) {
diff --git a/src/gpu/effects/GrDitherEffect.h b/src/gpu/effects/GrDitherEffect.h
index d3a4e86486..529b5ec457 100644
--- a/src/gpu/effects/GrDitherEffect.h
+++ b/src/gpu/effects/GrDitherEffect.h
@@ -46,6 +46,8 @@ public:
}
return sk_sp<GrFragmentProcessor>(new GrDitherEffect(rangeType));
}
+ GrDitherEffect(const GrDitherEffect& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "DitherEffect"; }
private:
diff --git a/src/gpu/effects/GrEllipseEffect.cpp b/src/gpu/effects/GrEllipseEffect.cpp
index ebc3bf7e37..edf12d27dd 100644
--- a/src/gpu/effects/GrEllipseEffect.cpp
+++ b/src/gpu/effects/GrEllipseEffect.cpp
@@ -113,6 +113,16 @@ bool GrEllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
if (fRadii != that.fRadii) return false;
return true;
}
+GrEllipseEffect::GrEllipseEffect(const GrEllipseEffect& src)
+ : INHERITED(src.optimizationFlags())
+ , fEdgeType(src.fEdgeType)
+ , fCenter(src.fCenter)
+ , fRadii(src.fRadii) {
+ this->initClassID<GrEllipseEffect>();
+}
+sk_sp<GrFragmentProcessor> GrEllipseEffect::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrEllipseEffect(*this));
+}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrEllipseEffect);
#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrEllipseEffect::TestCreate(GrProcessorTestData* testData) {
diff --git a/src/gpu/effects/GrEllipseEffect.h b/src/gpu/effects/GrEllipseEffect.h
index 980ba533be..28586561da 100644
--- a/src/gpu/effects/GrEllipseEffect.h
+++ b/src/gpu/effects/GrEllipseEffect.h
@@ -23,6 +23,8 @@ public:
static sk_sp<GrFragmentProcessor> Make(int edgeType, SkPoint center, SkPoint radii) {
return sk_sp<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii));
}
+ GrEllipseEffect(const GrEllipseEffect& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "EllipseEffect"; }
private:
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index bbac5b5f4c..bd2b80529a 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -70,6 +70,19 @@ bool GrSimpleTextureEffect::onIsEqual(const GrFragmentProcessor& other) const {
if (fMatrix != that.fMatrix) return false;
return true;
}
+GrSimpleTextureEffect::GrSimpleTextureEffect(const GrSimpleTextureEffect& src)
+ : INHERITED(src.optimizationFlags())
+ , fImage(src.fImage)
+ , fColorXform(src.fColorXform)
+ , fMatrix(src.fMatrix)
+ , fImageCoordTransform(src.fImageCoordTransform) {
+ this->initClassID<GrSimpleTextureEffect>();
+ this->addTextureSampler(&fImage);
+ this->addCoordTransform(&fImageCoordTransform);
+}
+sk_sp<GrFragmentProcessor> GrSimpleTextureEffect::clone() const {
+ return sk_sp<GrFragmentProcessor>(new GrSimpleTextureEffect(*this));
+}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSimpleTextureEffect);
#if GR_TEST_UTILS
sk_sp<GrFragmentProcessor> GrSimpleTextureEffect::TestCreate(GrProcessorTestData* testData) {
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index 41d7af772c..25ef1c5bd0 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -47,6 +47,8 @@ public:
return sk_sp<GrFragmentProcessor>(
new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix, p));
}
+ GrSimpleTextureEffect(const GrSimpleTextureEffect& src);
+ sk_sp<GrFragmentProcessor> clone() const override;
const char* name() const override { return "SimpleTextureEffect"; }
private:
diff --git a/src/sksl/README b/src/sksl/README
index 012895412e..329fa08ad7 100644
--- a/src/sksl/README
+++ b/src/sksl/README
@@ -83,6 +83,7 @@ Within an '.fp' fragment processor file:
@emitCode (extra code for the emitCode function)
@fields (extra private fields, each terminated with a semicolon)
@make (replaces the default Make function)
+ @clone (replaces the default clone() function)
@setData(<pdman>) (extra code for the setData function, where <pdman> is
the name of the GrGLSLProgramDataManager)
@test(<testData>) (the body of the TestCreate function, where <testData> is
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index 7c10606f79..2276ce372e 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -302,11 +302,13 @@ void CPPCodeGenerator::writeSetting(const Setting& s) {
}
}
-void CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
+bool CPPCodeGenerator::writeSection(const char* name, const char* prefix) {
const Section* s = fSectionAndParameterHelper.getSection(name);
if (s) {
this->writef("%s%s", prefix, s->fText.c_str());
+ return true;
}
+ return false;
}
void CPPCodeGenerator::writeProgramElement(const ProgramElement& p) {
@@ -503,6 +505,46 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
this->write(" }\n");
}
+void CPPCodeGenerator::writeClone() {
+ if (!this->writeSection(CLONE_SECTION)) {
+ if (fSectionAndParameterHelper.getSection(FIELDS_SECTION)) {
+ fErrors.error(Position(1, 1), "fragment processors with custom @fields must also have "
+ "a custom @clone");
+ }
+ this->writef("%s::%s(const %s& src)\n"
+ ": INHERITED(src.optimizationFlags())", fFullName.c_str(), fFullName.c_str(),
+ fFullName.c_str());
+ for (const auto& param : fSectionAndParameterHelper.getParameters()) {
+ String fieldName = HCodeGenerator::FieldName(param->fName.c_str());
+ this->writef("\n, %s(%s)",
+ fieldName.c_str(),
+ ("src." + fieldName).c_str());
+ }
+ for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
+ String fieldName = HCodeGenerator::FieldName(s->fArgument.c_str());
+ this->writef("\n, %sCoordTransform(src.%sCoordTransform)", fieldName.c_str(),
+ fieldName.c_str());
+ }
+ this->writef(" {\n"
+ " this->initClassID<%s>();\n",
+ fFullName.c_str());
+ for (const auto& param : fSectionAndParameterHelper.getParameters()) {
+ if (param->fType.kind() == Type::kSampler_Kind) {
+ this->writef(" this->addTextureSampler(&%s);\n",
+ HCodeGenerator::FieldName(param->fName.c_str()).c_str());
+ }
+ }
+ for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
+ String field = HCodeGenerator::FieldName(s->fArgument.c_str());
+ this->writef(" this->addCoordTransform(&%sCoordTransform);\n", field.c_str());
+ }
+ this->write("}\n");
+ this->writef("sk_sp<GrFragmentProcessor> %s::clone() const {\n", fFullName.c_str());
+ this->writef(" return sk_sp<GrFragmentProcessor>(new %s(*this));\n", fFullName.c_str());
+ this->write("}\n");
+ }
+}
+
void CPPCodeGenerator::writeTest() {
const Section* test = fSectionAndParameterHelper.getSection(TEST_CODE_SECTION);
if (test) {
@@ -639,6 +681,7 @@ bool CPPCodeGenerator::generateCode() {
}
this->write(" return true;\n"
"}\n");
+ this->writeClone();
this->writeTest();
this->writeSection(CPP_END_SECTION);
this->write("#endif\n");
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index 8b30151c71..b4f31ba1b0 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -27,7 +27,7 @@ private:
void writef(const char* s, ...) SKSL_PRINTF_LIKE(2, 3);
- void writeSection(const char* name, const char* prefix = "");
+ bool writeSection(const char* name, const char* prefix = "");
void writeHeader() override;
@@ -72,6 +72,8 @@ private:
void writeGetKey();
+ void writeClone();
+
void writeTest();
String fName;
diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp
index 65dbf78025..22f4fd80ce 100644
--- a/src/sksl/SkSLHCodeGenerator.cpp
+++ b/src/sksl/SkSLHCodeGenerator.cpp
@@ -250,9 +250,11 @@ bool HCodeGenerator::generateCode() {
FieldType(param->fType).c_str(), name, FieldName(name).c_str());
}
this->writeMake();
- this->writef(" const char* name() const override { return \"%s\"; }\n"
+ this->writef(" %s(const %s& src);\n"
+ " sk_sp<GrFragmentProcessor> clone() const override;\n"
+ " const char* name() const override { return \"%s\"; }\n"
"private:\n",
- fName.c_str());
+ fFullName.c_str(), fFullName.c_str(), fName.c_str());
this->writeConstructor();
this->writef(" GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
" void onGetGLSLProcessorKey(const GrShaderCaps&,"
diff --git a/src/sksl/SkSLSectionAndParameterHelper.h b/src/sksl/SkSLSectionAndParameterHelper.h
index bbe007c46e..f70b82c439 100644
--- a/src/sksl/SkSLSectionAndParameterHelper.h
+++ b/src/sksl/SkSLSectionAndParameterHelper.h
@@ -18,6 +18,7 @@
namespace SkSL {
#define CLASS_SECTION "class"
+#define CLONE_SECTION "clone"
#define CONSTRUCTOR_SECTION "constructor"
#define CONSTRUCTOR_CODE_SECTION "constructorCode"
#define CONSTRUCTOR_PARAMS_SECTION "constructorParams"
@@ -110,6 +111,7 @@ public:
static bool IsSupportedSection(const char* name) {
return !strcmp(name, CLASS_SECTION) ||
+ !strcmp(name, CLONE_SECTION) ||
!strcmp(name, CONSTRUCTOR_SECTION) ||
!strcmp(name, CONSTRUCTOR_CODE_SECTION) ||
!strcmp(name, CONSTRUCTOR_PARAMS_SECTION) ||
diff --git a/tests/SkSLFPTest.cpp b/tests/SkSLFPTest.cpp
index 7a1d371738..82bcb10b71 100644
--- a/tests/SkSLFPTest.cpp
+++ b/tests/SkSLFPTest.cpp
@@ -88,6 +88,8 @@ DEF_TEST(SkSLFPHelloWorld, r) {
" static sk_sp<GrFragmentProcessor> Make() {\n"
" return sk_sp<GrFragmentProcessor>(new GrTest());\n"
" }\n"
+ " GrTest(const GrTest& src);\n"
+ " sk_sp<GrFragmentProcessor> clone() const override;\n"
" const char* name() const override { return \"Test\"; }\n"
"private:\n"
" GrTest()\n"
@@ -148,6 +150,13 @@ DEF_TEST(SkSLFPHelloWorld, r) {
" (void) that;\n"
" return true;\n"
"}\n"
+ "GrTest::GrTest(const GrTest& src)\n"
+ ": INHERITED(src.optimizationFlags()) {\n"
+ " this->initClassID<GrTest>();\n"
+ "}\n"
+ "sk_sp<GrFragmentProcessor> GrTest::clone() const {\n"
+ " return sk_sp<GrFragmentProcessor>(new GrTest(*this));\n"
+ "}\n"
"#endif\n"
});
}
@@ -287,6 +296,7 @@ DEF_TEST(SkSLFPSections, r) {
});
test(r,
"@fields { fields section }"
+ "@clone { }"
"void main() {"
"sk_OutColor = float4(1);"
"}",