SkSL FPs now support child processors, converted ArithmeticFP to SkSL

Bug: skia:
Change-Id: I34ed3480073d05762a7d4692aeee4b87e454ce52
Reviewed-on: https://skia-review.googlesource.com/57961
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Ethan Nicholas 2017-10-10 16:30:21 -04:00 committed by Skia Commit-Bot
parent f88c12ea20
commit c9472af858
14 changed files with 304 additions and 138 deletions

View File

@ -310,6 +310,8 @@ skia_gpu_sources = [
"$_src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp",
"$_src/gpu/ccpr/GrCoverageCountingPathRenderer.h",
"$_src/gpu/effects/GrArithmeticFP.cpp",
"$_src/gpu/effects/GrArithmeticFP.h",
"$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp",
"$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.h",
"$_src/gpu/effects/GrCircleEffect.cpp",

View File

@ -27,6 +27,7 @@ skia_sksl_sources = [
skia_gpu_processor_sources = [
"$_src/effects/GrAlphaThresholdFragmentProcessor.fp",
"$_src/effects/GrCircleBlurFragmentProcessor.fp",
"$_src/gpu/effects/GrArithmeticFP.fp",
"$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp",
"$_src/gpu/effects/GrCircleEffect.fp",
"$_src/gpu/effects/GrConfigConversionEffect.fp",

View File

@ -20,6 +20,7 @@
#include "GrRenderTargetContext.h"
#include "GrTextureProxy.h"
#include "SkGr.h"
#include "effects/GrArithmeticFP.h"
#include "effects/GrConstColorProcessor.h"
#include "effects/GrTextureDomain.h"
#include "glsl/GrGLSLFragmentProcessor.h"
@ -261,116 +262,8 @@ SkIRect ArithmeticImageFilterImpl::onFilterBounds(const SkIRect& src,
#if SK_SUPPORT_GPU
namespace {
class ArithmeticFP : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(float k1, float k2, float k3, float k4,
bool enforcePMColor,
std::unique_ptr<GrFragmentProcessor> dst) {
return std::unique_ptr<GrFragmentProcessor>(
new ArithmeticFP(k1, k2, k3, k4, enforcePMColor, std::move(dst)));
}
~ArithmeticFP() override {}
const char* name() const override { return "Arithmetic"; }
SkString dumpInfo() const override {
SkString str;
str.appendf("K1: %.2f K2: %.2f K3: %.2f K4: %.2f", fK1, fK2, fK3, fK4);
return str;
}
std::unique_ptr<GrFragmentProcessor> clone() const override {
return Make(fK1, fK2, fK3, fK4, fEnforcePMColor, this->childProcessor(0).clone());
}
float k1() const { return fK1; }
float k2() const { return fK2; }
float k3() const { return fK3; }
float k4() const { return fK4; }
bool enforcePMColor() const { return fEnforcePMColor; }
private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
class GLSLFP : public GrGLSLFragmentProcessor {
public:
void emitCode(EmitArgs& args) override {
const ArithmeticFP& arith = args.fFp.cast<ArithmeticFP>();
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
SkString dstColor("dstColor");
this->emitChild(0, &dstColor, args);
fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
"k");
const char* kUni = args.fUniformHandler->getUniformCStr(fKUni);
// We don't try to optimize for this case at all
if (!args.fInputColor) {
fragBuilder->codeAppend("const half4 src = half4(1);");
} else {
fragBuilder->codeAppendf("half4 src = %s;", args.fInputColor);
}
fragBuilder->codeAppendf("half4 dst = %s;", dstColor.c_str());
fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
args.fOutputColor, kUni, kUni, kUni, kUni);
fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", args.fOutputColor,
args.fOutputColor);
if (arith.fEnforcePMColor) {
fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);", args.fOutputColor,
args.fOutputColor, args.fOutputColor);
}
}
protected:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& proc) override {
const ArithmeticFP& arith = proc.cast<ArithmeticFP>();
pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
}
private:
GrGLSLProgramDataManager::UniformHandle fKUni;
};
return new GLSLFP;
}
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
b->add32(fEnforcePMColor ? 1 : 0);
}
bool onIsEqual(const GrFragmentProcessor& fpBase) const override {
const ArithmeticFP& fp = fpBase.cast<ArithmeticFP>();
return fK1 == fp.fK1 && fK2 == fp.fK2 && fK3 == fp.fK3 && fK4 == fp.fK4 &&
fEnforcePMColor == fp.fEnforcePMColor;
}
// This could implement the const input -> const output optimization but it's unlikely to help.
ArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
std::unique_ptr<GrFragmentProcessor> dst)
: INHERITED(kArithmeticFP_ClassID, kNone_OptimizationFlags)
, fK1(k1)
, fK2(k2)
, fK3(k3)
, fK4(k4)
, fEnforcePMColor(enforcePMColor) {
SkASSERT(dst);
SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(dst));
SkASSERT(0 == dstIndex);
}
float fK1, fK2, fK3, fK4;
bool fEnforcePMColor;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
typedef GrFragmentProcessor INHERITED;
};
}
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> ArithmeticFP::TestCreate(GrProcessorTestData* d) {
std::unique_ptr<GrFragmentProcessor> GrArithmeticFP::TestCreate(GrProcessorTestData* d) {
float k1 = d->fRandom->nextF();
float k2 = d->fRandom->nextF();
float k3 = d->fRandom->nextF();
@ -378,11 +271,11 @@ std::unique_ptr<GrFragmentProcessor> ArithmeticFP::TestCreate(GrProcessorTestDat
bool enforcePMColor = d->fRandom->nextBool();
std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
return ArithmeticFP::Make(k1, k2, k3, k4, enforcePMColor, std::move(dst));
return GrArithmeticFP::Make(k1, k2, k3, k4, enforcePMColor, std::move(dst));
}
#endif
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ArithmeticFP);
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU(
SkSpecialImage* source,
@ -435,7 +328,7 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU(
paint.addColorFragmentProcessor(std::move(foregroundFP));
std::unique_ptr<GrFragmentProcessor> xferFP =
ArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP));
GrArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP));
// A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed
if (xferFP) {

View File

@ -66,7 +66,6 @@ class GrProcessor {
public:
enum ClassID {
kAARectEffect_ClassID,
kArithmeticFP_ClassID,
kBigKeyProcessor_ClassID,
kBlockInputFragmentProcessor_ClassID,
kCircleGeometryProcessor_ClassID,
@ -91,6 +90,7 @@ public:
kFocalOutside2PtConicalEffect_ClassID,
kGP_ClassID,
kGrAlphaThresholdFragmentProcessor_ClassID,
kGrArithmeticFP_ClassID,
kGrBicubicEffect_ClassID,
kGrBitmapTextGeoProc_ClassID,
kGrBlurredEdgeFragmentProcessor_ClassID,

View File

@ -0,0 +1,94 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* This file was autogenerated from GrArithmeticFP.fp; do not modify.
*/
#include "GrArithmeticFP.h"
#if SK_SUPPORT_GPU
#include "glsl/GrGLSLColorSpaceXformHelper.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "SkSLCPP.h"
#include "SkSLUtil.h"
class GrGLSLArithmeticFP : public GrGLSLFragmentProcessor {
public:
GrGLSLArithmeticFP() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrArithmeticFP& _outer = args.fFp.cast<GrArithmeticFP>();
(void)_outer;
fKVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
kDefault_GrSLPrecision, "k");
SkString _child0("_child0");
this->emitChild(0, &_child0, args);
fragBuilder->codeAppendf(
"half4 dst = %s;\n%s = half4(clamp(float4(float4(((%s.x * float4(%s)) * dst + %s.y "
"* float4(%s)) + %s.z * float4(dst)) + %s.w), 0.0, 1.0));\nif (%s) {\n %s.xyz = "
"half3(min(float3(%s.xyz), float(%s.w)));\n}\n",
_child0.c_str(), args.fOutputColor, args.fUniformHandler->getUniformCStr(fKVar),
args.fInputColor ? args.fInputColor : "half4(1)",
args.fUniformHandler->getUniformCStr(fKVar),
args.fInputColor ? args.fInputColor : "half4(1)",
args.fUniformHandler->getUniformCStr(fKVar),
args.fUniformHandler->getUniformCStr(fKVar),
(_outer.enforcePMColor() ? "true" : "false"), args.fOutputColor, args.fOutputColor,
args.fOutputColor);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrArithmeticFP& _outer = _proc.cast<GrArithmeticFP>();
auto k1 = _outer.k1();
(void)k1;
auto k2 = _outer.k2();
(void)k2;
auto k3 = _outer.k3();
(void)k3;
auto k4 = _outer.k4();
(void)k4;
auto enforcePMColor = _outer.enforcePMColor();
(void)enforcePMColor;
UniformHandle& k = fKVar;
(void)k;
pdman.set4f(k, k1, k2, k3, k4);
}
UniformHandle fKVar;
};
GrGLSLFragmentProcessor* GrArithmeticFP::onCreateGLSLInstance() const {
return new GrGLSLArithmeticFP();
}
void GrArithmeticFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
b->add32(fEnforcePMColor);
}
bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& other) const {
const GrArithmeticFP& that = other.cast<GrArithmeticFP>();
(void)that;
if (fK1 != that.fK1) return false;
if (fK2 != that.fK2) return false;
if (fK3 != that.fK3) return false;
if (fK4 != that.fK4) return false;
if (fEnforcePMColor != that.fEnforcePMColor) return false;
return true;
}
GrArithmeticFP::GrArithmeticFP(const GrArithmeticFP& src)
: INHERITED(kGrArithmeticFP_ClassID, src.optimizationFlags())
, fK1(src.fK1)
, fK2(src.fK2)
, fK3(src.fK3)
, fK4(src.fK4)
, fEnforcePMColor(src.fEnforcePMColor) {
this->registerChildProcessor(src.childProcessor(0).clone());
}
std::unique_ptr<GrFragmentProcessor> GrArithmeticFP::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrArithmeticFP(*this));
}
#endif

View File

@ -0,0 +1,20 @@
in float k1;
in float k2;
in float k3;
in float k4;
layout(key) in bool enforcePMColor;
in fragmentProcessor child;
uniform float4 k;
void main() {
half4 dst = process(child);
sk_OutColor = clamp(k.x * sk_InColor * dst + k.y * sk_InColor + k.z * dst + k.w, 0, 1);
if (enforcePMColor) {
sk_OutColor.rgb = min(sk_OutColor.rgb, sk_OutColor.a);
}
}
@setData(pdman) {
pdman.set4f(k, k1, k2, k3, k4);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* This file was autogenerated from GrArithmeticFP.fp; do not modify.
*/
#ifndef GrArithmeticFP_DEFINED
#define GrArithmeticFP_DEFINED
#include "SkTypes.h"
#if SK_SUPPORT_GPU
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
#include "GrColorSpaceXform.h"
class GrArithmeticFP : public GrFragmentProcessor {
public:
float k1() const { return fK1; }
float k2() const { return fK2; }
float k3() const { return fK3; }
float k4() const { return fK4; }
bool enforcePMColor() const { return fEnforcePMColor; }
static std::unique_ptr<GrFragmentProcessor> Make(float k1, float k2, float k3, float k4,
bool enforcePMColor,
std::unique_ptr<GrFragmentProcessor> child) {
return std::unique_ptr<GrFragmentProcessor>(
new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, child->clone()));
}
GrArithmeticFP(const GrArithmeticFP& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "ArithmeticFP"; }
private:
GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
std::unique_ptr<GrFragmentProcessor> child)
: INHERITED(kGrArithmeticFP_ClassID, kNone_OptimizationFlags)
, fK1(k1)
, fK2(k2)
, fK3(k3)
, fK4(k4)
, fEnforcePMColor(enforcePMColor) {
this->registerChildProcessor(std::move(child));
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
float fK1;
float fK2;
float fK3;
float fK4;
bool fEnforcePMColor;
typedef GrFragmentProcessor INHERITED;
};
#endif
#endif

View File

@ -246,6 +246,36 @@ void CPPCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
}
void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
if (c.fFunction.fBuiltin && c.fFunction.fName == "process") {
ASSERT(c.fArguments.size() == 1);
ASSERT(Expression::kVariableReference_Kind == c.fArguments[0]->fKind);
int index = 0;
bool found = false;
for (const auto& p : fProgram.fElements) {
if (ProgramElement::kVar_Kind == p->fKind) {
const VarDeclarations* decls = (const VarDeclarations*) p.get();
for (const auto& raw : decls->fVars) {
VarDeclaration& decl = (VarDeclaration&) *raw;
if (decl.fVar == &((VariableReference&) *c.fArguments[0]).fVariable) {
found = true;
} else if (decl.fVar->fType == *fContext.fFragmentProcessor_Type) {
++index;
}
}
}
if (found) {
break;
}
}
ASSERT(found);
String childName = "_child" + to_string(index);
fExtraEmitCodeCode += " SkString " + childName + "(\"" + childName + "\");\n" +
" this->emitChild(" + to_string(index) + ", &" + childName +
", args);\n";
this->write("%s");
fFormatArgs.push_back(childName + ".c_str()");
return;
}
if (c.fFunction.fBuiltin && c.fFunction.fName == "COLORSPACE") {
String tmpVar = "_tmpVar" + to_string(++fVarCount);
fFunctionHeader += "half4 " + tmpVar + ";";
@ -383,8 +413,13 @@ void CPPCodeGenerator::writePrivateVars() {
for (const auto& raw : decls->fVars) {
VarDeclaration& decl = (VarDeclaration&) *raw;
if (is_private(*decl.fVar)) {
if (decl.fVar->fType == *fContext.fFragmentProcessor_Type) {
fErrors.error(decl.fOffset,
"fragmentProcessor variables must be declared 'in'");
return;
}
this->writef("%s %s;\n",
HCodeGenerator::FieldType(decl.fVar->fType).c_str(),
HCodeGenerator::FieldType(fContext, decl.fVar->fType).c_str(),
String(decl.fVar->fName).c_str());
}
}
@ -477,6 +512,8 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
" fColorSpaceHelper.setData(%s, _outer.%s().get());\n"
" }\n",
pdman, name);
} else if (u->fType == *fContext.fFragmentProcessor_Type) {
// do nothing
} else {
this->writef(" %s.set1f(%sVar, _outer.%s());\n",
pdman, HCodeGenerator::FieldName(name).c_str(), name);
@ -498,7 +535,8 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
this->writef(" UniformHandle& %s = %sVar;\n"
" (void) %s;\n",
name, HCodeGenerator::FieldName(name).c_str(), name);
} else if (SectionAndParameterHelper::IsParameter(*decl.fVar)) {
} else if (SectionAndParameterHelper::IsParameter(*decl.fVar) &&
decl.fVar->fType != *fContext.fFragmentProcessor_Type) {
if (!wroteProcessor) {
this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName,
fullName);
@ -526,10 +564,13 @@ void CPPCodeGenerator::writeClone() {
": INHERITED(k%s_ClassID, src.optimizationFlags())", fFullName.c_str(),
fFullName.c_str(), fFullName.c_str(), fFullName.c_str());
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
if (param->fType == *fContext.fFragmentProcessor_Type) {
continue;
}
String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str());
this->writef("\n, %s(%s)",
this->writef("\n, %s(src.%s)",
fieldName.c_str(),
("src." + fieldName).c_str());
fieldName.c_str());
}
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
String fieldName = HCodeGenerator::FieldName(s->fArgument.c_str());
@ -537,10 +578,14 @@ void CPPCodeGenerator::writeClone() {
fieldName.c_str());
}
this->writef(" {\n");
int childCount = 0;
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
if (param->fType.kind() == Type::kSampler_Kind) {
this->writef(" this->addTextureSampler(&%s);\n",
HCodeGenerator::FieldName(String(param->fName).c_str()).c_str());
} else if (param->fType == *fContext.fFragmentProcessor_Type) {
this->writef(" this->registerChildProcessor(src.childProcessor(%d).clone());"
"\n", childCount++);
}
}
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
@ -687,6 +732,9 @@ bool CPPCodeGenerator::generateCode() {
" (void) that;\n",
fullName, fullName, fullName);
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
if (param->fType == *fContext.fFragmentProcessor_Type) {
continue;
}
String nameString(param->fName);
const char* name = nameString.c_str();
this->writef(" if (%s != that.%s) return false;\n",

View File

@ -185,6 +185,7 @@ Compiler::Compiler(Flags flags)
ADD_TYPE(GSampler2DArrayShadow);
ADD_TYPE(GSamplerCubeArrayShadow);
ADD_TYPE(ColorSpaceXform);
ADD_TYPE(FragmentProcessor);
StringFragment skCapsName("sk_Caps");
Variable* skCaps = new Variable(-1, Modifiers(), skCapsName,
@ -1246,7 +1247,7 @@ bool Compiler::toCPP(const Program& program, String name, OutputStream& out) {
bool Compiler::toH(const Program& program, String name, OutputStream& out) {
fSource = program.fSource.get();
HCodeGenerator cg(&program, this, name, &out);
HCodeGenerator cg(&fContext, &program, this, name, &out);
bool result = cg.generateCode();
fSource = nullptr;
this->writeErrorCount();

View File

@ -185,6 +185,7 @@ public:
, fSkCaps_Type(new Type("$sk_Caps"))
, fSkArgs_Type(new Type("$sk_Args"))
, fColorSpaceXform_Type(new Type("colorSpaceXform", *fFloat_Type, 4, 4))
, fFragmentProcessor_Type(new Type("fragmentProcessor"))
, fDefined_Expression(new Defined(*fInvalid_Type)) {}
static std::vector<const Type*> static_type(const Type& t) {
@ -333,6 +334,7 @@ public:
const std::unique_ptr<Type> fSkCaps_Type;
const std::unique_ptr<Type> fSkArgs_Type;
const std::unique_ptr<Type> fColorSpaceXform_Type;
const std::unique_ptr<Type> fFragmentProcessor_Type;
// dummy expression used to mark that a variable has a value during dataflow analysis (when it
// could have several different values, or the analyzer is otherwise unable to assign it a

View File

@ -15,37 +15,45 @@
namespace SkSL {
HCodeGenerator::HCodeGenerator(const Program* program, ErrorReporter* errors, String name,
OutputStream* out)
HCodeGenerator::HCodeGenerator(const Context* context, const Program* program,
ErrorReporter* errors, String name, OutputStream* out)
: INHERITED(program, errors, out)
, fContext(*context)
, fName(std::move(name))
, fFullName(String::printf("Gr%s", fName.c_str()))
, fSectionAndParameterHelper(*program, *errors) {}
String HCodeGenerator::ParameterType(const Type& type) {
if (type.name() == "float" || type.name() == "half") {
String HCodeGenerator::ParameterType(const Context& context, const Type& type) {
if (type == *context.fFloat_Type || type == *context.fHalf_Type) {
return "float";
} else if (type.name() == "float2" || type.name() == "half2") {
} else if (type == *context.fFloat2_Type || type == *context.fHalf2_Type) {
return "SkPoint";
} else if (type.name() == "int4" || type.name() == "short4") {
} else if (type == *context.fInt4_Type || type == *context.fShort4_Type) {
return "SkIRect";
} else if (type.name() == "float4" || type.name() == "half4") {
} else if (type == *context.fFloat4_Type || type == *context.fHalf4_Type) {
return "SkRect";
} else if (type.name() == "float4x4" || type.name() == "half4x4") {
} else if (type == *context.fFloat4x4_Type || type == *context.fHalf4x4_Type) {
return "SkMatrix44";
} else if (type.kind() == Type::kSampler_Kind) {
return "sk_sp<GrTextureProxy>";
} else if (type.name() == "colorSpaceXform") {
} else if (type == *context.fColorSpaceXform_Type) {
return "sk_sp<GrColorSpaceXform>";
} else if (type == *context.fFragmentProcessor_Type) {
return "std::unique_ptr<GrFragmentProcessor>";
}
return type.name();
}
String HCodeGenerator::FieldType(const Type& type) {
String HCodeGenerator::FieldType(const Context& context, const Type& type) {
if (type.kind() == Type::kSampler_Kind) {
return "TextureSampler";
} else if (type == *context.fFragmentProcessor_Type) {
// we don't store fragment processors in fields, they get registered via
// registerChildProcessor instead
ASSERT(false);
return "<error>";
}
return ParameterType(type);
return ParameterType(context, type);
}
void HCodeGenerator::writef(const char* s, va_list va) {
@ -128,7 +136,7 @@ void HCodeGenerator::writeMake() {
this->writef(" static std::unique_ptr<GrFragmentProcessor> Make(");
separator = "";
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
this->writef("%s%s %s", separator, ParameterType(fContext, param->fType).c_str(),
String(param->fName).c_str());
separator = ", ";
}
@ -138,7 +146,11 @@ void HCodeGenerator::writeMake() {
fFullName.c_str());
separator = "";
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
this->writef("%s%s", separator, String(param->fName).c_str());
if (param->fType == *fContext.fFragmentProcessor_Type) {
this->writef("%s%s->clone()", separator, String(param->fName).c_str());
} else {
this->writef("%s%s", separator, String(param->fName).c_str());
}
separator = ", ";
}
this->writeExtraConstructorParams(separator);
@ -166,7 +178,7 @@ void HCodeGenerator::writeConstructor() {
this->writef(" %s(", fFullName.c_str());
const char* separator = "";
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
this->writef("%s%s %s", separator, ParameterType(param->fType).c_str(),
this->writef("%s%s %s", separator, ParameterType(fContext, param->fType).c_str(),
String(param->fName).c_str());
separator = ", ";
}
@ -190,6 +202,8 @@ void HCodeGenerator::writeConstructor() {
}
}
this->writef(")");
} else if (param->fType == *fContext.fFragmentProcessor_Type) {
// do nothing
} else {
this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
}
@ -205,6 +219,9 @@ void HCodeGenerator::writeConstructor() {
if (param->fType.kind() == Type::kSampler_Kind) {
this->writef(" this->addTextureSampler(&%s);\n",
FieldName(String(param->fName).c_str()).c_str());
} else if (param->fType == *fContext.fFragmentProcessor_Type) {
this->writef(" this->registerChildProcessor(std::move(%s));",
String(param->fName).c_str());
}
}
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
@ -217,7 +234,10 @@ void HCodeGenerator::writeConstructor() {
void HCodeGenerator::writeFields() {
this->writeSection(FIELDS_SECTION);
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
this->writef(" %s %s;\n", FieldType(param->fType).c_str(),
if (param->fType == *fContext.fFragmentProcessor_Type) {
continue;
}
this->writef(" %s %s;\n", FieldType(fContext, param->fType).c_str(),
FieldName(String(param->fName).c_str()).c_str());
}
for (const Section* s : fSectionAndParameterHelper.getSections(COORD_TRANSFORM_SECTION)) {
@ -243,13 +263,14 @@ bool HCodeGenerator::generateCode() {
fFullName.c_str());
this->writeSection(CLASS_SECTION);
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
if (param->fType.kind() == Type::kSampler_Kind) {
if (param->fType.kind() == Type::kSampler_Kind ||
param->fType.kind() == Type::kOther_Kind) {
continue;
}
String nameString(param->fName);
const char* name = nameString.c_str();
this->writef(" %s %s() const { return %s; }\n",
FieldType(param->fType).c_str(), name, FieldName(name).c_str());
FieldType(fContext, param->fType).c_str(), name, FieldName(name).c_str());
}
this->writeMake();
this->writef(" %s(const %s& src);\n"

View File

@ -32,13 +32,14 @@ namespace SkSL {
class HCodeGenerator : public CodeGenerator {
public:
HCodeGenerator(const Program* program, ErrorReporter* errors, String name, OutputStream* out);
HCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
String name, OutputStream* out);
bool generateCode() override;
static String ParameterType(const Type& type);
static String ParameterType(const Context& context, const Type& type);
static String FieldType(const Type& type);
static String FieldType(const Context& context, const Type& type);
static String FieldName(const char* varName) {
return String::printf("f%c%s", toupper(varName[0]), varName + 1);
@ -63,6 +64,7 @@ private:
void failOnSection(const char* section, const char* msg);
const Context& fContext;
String fName;
String fFullName;
SectionAndParameterHelper fSectionAndParameterHelper;

View File

@ -22,4 +22,6 @@ layout(builtin=10005) float2[] sk_TransformedCoords2D;
layout(builtin=10006) sampler2D[] sk_TextureSamplers;
half4 COLORSPACE(half4 color, colorSpaceXform colorSpace);
half4 process(fragmentProcessor fp);
)

View File

@ -402,4 +402,26 @@ DEF_TEST(SkSLFPLayoutWhen, r) {
}
DEF_TEST(SkSLFPChildProcessors, r) {
test(r,
"in fragmentProcessor child1;"
"in fragmentProcessor child2;"
"void main() {"
" sk_OutColor = process(child1) * process(child2);"
"}",
*SkSL::ShaderCapsFactory::Default(),
{
"this->registerChildProcessor(std::move(child1));",
"this->registerChildProcessor(std::move(child2));"
},
{
"SkString _child0(\"_child0\");",
"this->emitChild(0, &_child0, args);",
"SkString _child1(\"_child1\");",
"this->emitChild(1, &_child1, args);",
"this->registerChildProcessor(src.childProcessor(0).clone());",
"this->registerChildProcessor(src.childProcessor(1).clone());"
});
}
#endif