SkSL: Add TypeKind::kFragmentProcessor
Change-Id: I1d77b9e10f9c92712f01473d3ae87b191cabb135 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/391303 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
006fc6a2cd
commit
3967588d75
@ -183,7 +183,7 @@ SkRuntimeEffect::Result SkRuntimeEffect::Make(SkString sksl, const Options& opti
|
||||
: 1});
|
||||
}
|
||||
// Fragment Processors (aka 'shader'): These are child effects
|
||||
else if (&varType == ctx.fTypes.fFragmentProcessor.get()) {
|
||||
else if (varType.isFragmentProcessor()) {
|
||||
children.push_back(var.name());
|
||||
sampleUsages.push_back(SkSL::Analysis::GetSampleUsage(*program, var));
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
if (var.type().isOpaque()) {
|
||||
// Nothing to do. The only opaque type we should see is fragmentProcessor, and
|
||||
// those (children) are handled specially, above.
|
||||
SkASSERT(var.type() == *fContext.fTypes.fFragmentProcessor);
|
||||
SkASSERT(var.type().isFragmentProcessor());
|
||||
return String(var.name());
|
||||
}
|
||||
|
||||
|
@ -83,12 +83,17 @@ std::unique_ptr<Type> BuiltinTypes::MakeVoidType(const char* name) {
|
||||
return std::unique_ptr<Type>(new Type(name, "v", Type::TypeKind::kVoid));
|
||||
}
|
||||
|
||||
/** Create a fragment processor type. */
|
||||
std::unique_ptr<Type> BuiltinTypes::MakeFragmentProcessorType(const char* name) {
|
||||
return std::unique_ptr<Type>(new Type(name, "fp", Type::TypeKind::kFragmentProcessor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an "other" (special) type with the given name. These types cannot be directly
|
||||
* referenced from user code.
|
||||
*/
|
||||
std::unique_ptr<Type> BuiltinTypes::MakeOtherType(const char* name) {
|
||||
return std::unique_ptr<Type>(new Type(name));
|
||||
return std::unique_ptr<Type>(new Type(name, "O", Type::TypeKind::kOther));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,6 +266,6 @@ BuiltinTypes::BuiltinTypes()
|
||||
, fBVec(MakeGenericType("$bvec",
|
||||
{fInvalid.get(), fBool2.get(), fBool3.get(), fBool4.get()}))
|
||||
, fSkCaps(MakeOtherType("$sk_Caps"))
|
||||
, fFragmentProcessor(MakeOtherType("fragmentProcessor")) {}
|
||||
, fFragmentProcessor(MakeFragmentProcessorType("fragmentProcessor")) {}
|
||||
|
||||
} // namespace SkSL
|
||||
|
@ -155,6 +155,7 @@ private:
|
||||
static std::unique_ptr<Type> MakeSamplerType(const char* name, const Type& textureType);
|
||||
static std::unique_ptr<Type> MakeSeparateSamplerType(const char* name);
|
||||
static std::unique_ptr<Type> MakeOtherType(const char* name);
|
||||
static std::unique_ptr<Type> MakeFragmentProcessorType(const char* name);
|
||||
static std::unique_ptr<Type> MakeVoidType(const char* name);
|
||||
};
|
||||
|
||||
|
@ -353,7 +353,7 @@ int CPPCodeGenerator::getChildFPIndex(const Variable& var) const {
|
||||
p->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
|
||||
if (&decl.var() == &var) {
|
||||
return index;
|
||||
} else if (decl.var().type() == *fContext.fTypes.fFragmentProcessor) {
|
||||
} else if (decl.var().type().isFragmentProcessor()) {
|
||||
++index;
|
||||
}
|
||||
}
|
||||
@ -375,7 +375,7 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
|
||||
// Validity checks that are detected by function definition in sksl_fp.inc
|
||||
SkASSERT(arguments.size() >= 1 && arguments.size() <= 3);
|
||||
SkASSERT("fragmentProcessor" == arguments[0]->type().name());
|
||||
SkASSERT(arguments[0]->type().isFragmentProcessor());
|
||||
|
||||
// Actually fail during compilation if arguments with valid types are
|
||||
// provided that are not variable references, since sample() is a
|
||||
@ -669,7 +669,7 @@ void CPPCodeGenerator::writePrivateVars() {
|
||||
const GlobalVarDeclaration& global = p->as<GlobalVarDeclaration>();
|
||||
const Variable& var = global.declaration()->as<VarDeclaration>().var();
|
||||
if (is_private(var)) {
|
||||
if (var.type() == *fContext.fTypes.fFragmentProcessor) {
|
||||
if (var.type().isFragmentProcessor()) {
|
||||
fErrors.error(global.fOffset,
|
||||
"fragmentProcessor variables must be declared 'in'");
|
||||
return;
|
||||
@ -719,7 +719,8 @@ void CPPCodeGenerator::writePrivateVarValues() {
|
||||
|
||||
static bool is_accessible(const Variable& var) {
|
||||
const Type& type = var.type();
|
||||
return Type::TypeKind::kSampler != type.typeKind() &&
|
||||
return !type.isFragmentProcessor() &&
|
||||
Type::TypeKind::kSampler != type.typeKind() &&
|
||||
Type::TypeKind::kOther != type.typeKind();
|
||||
}
|
||||
|
||||
@ -1089,14 +1090,14 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) {
|
||||
" (void) %s;\n",
|
||||
name, HCodeGenerator::FieldName(name).c_str(), name);
|
||||
} else if (SectionAndParameterHelper::IsParameter(variable) &&
|
||||
variable.type() != *fContext.fTypes.fFragmentProcessor) {
|
||||
!variable.type().isFragmentProcessor()) {
|
||||
if (!wroteProcessor) {
|
||||
this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName,
|
||||
fullName);
|
||||
wroteProcessor = true;
|
||||
}
|
||||
|
||||
if (variable.type() != *fContext.fTypes.fFragmentProcessor) {
|
||||
if (!variable.type().isFragmentProcessor()) {
|
||||
this->writef(" auto %s = _outer.%s;\n"
|
||||
" (void) %s;\n",
|
||||
name, name, name);
|
||||
@ -1143,7 +1144,7 @@ void CPPCodeGenerator::writeClone() {
|
||||
fFullName.c_str(), fFullName.c_str(), fFullName.c_str());
|
||||
for (const Variable* param : fSectionAndParameterHelper.getParameters()) {
|
||||
String fieldName = HCodeGenerator::FieldName(String(param->name()).c_str());
|
||||
if (param->type() != *fContext.fTypes.fFragmentProcessor) {
|
||||
if (!param->type().isFragmentProcessor()) {
|
||||
this->writef("\n, %s(src.%s)",
|
||||
fieldName.c_str(),
|
||||
fieldName.c_str());
|
||||
@ -1187,7 +1188,7 @@ void CPPCodeGenerator::writeDumpInfo() {
|
||||
|
||||
for (const Variable* param : fSectionAndParameterHelper.getParameters()) {
|
||||
// dumpInfo() doesn't need to log child FPs.
|
||||
if (param->type() == *fContext.fTypes.fFragmentProcessor) {
|
||||
if (param->type().isFragmentProcessor()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1424,7 +1425,7 @@ bool CPPCodeGenerator::generateCode() {
|
||||
" (void) that;\n",
|
||||
fullName, fullName, fullName);
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
if (param->type() == *fContext.fTypes.fFragmentProcessor) {
|
||||
if (param->type().isFragmentProcessor()) {
|
||||
continue;
|
||||
}
|
||||
String nameString(param->name());
|
||||
|
@ -74,7 +74,7 @@ Layout::CType HCodeGenerator::ParameterCType(const Context& context, const Type&
|
||||
return Layout::CType::kSkM44;
|
||||
} else if (type.typeKind() == Type::TypeKind::kSampler) {
|
||||
return Layout::CType::kGrSurfaceProxyView;
|
||||
} else if (type == *context.fTypes.fFragmentProcessor) {
|
||||
} else if (type.isFragmentProcessor()) {
|
||||
return Layout::CType::kGrFragmentProcessor;
|
||||
}
|
||||
return Layout::CType::kDefault;
|
||||
@ -84,7 +84,7 @@ String HCodeGenerator::FieldType(const Context& context, const Type& type,
|
||||
const Layout& layout) {
|
||||
if (type.typeKind() == Type::TypeKind::kSampler) {
|
||||
return "TextureSampler";
|
||||
} else if (type == *context.fTypes.fFragmentProcessor) {
|
||||
} else if (type.isFragmentProcessor()) {
|
||||
// we don't store fragment processors in fields, they get registered via
|
||||
// registerChildProcessor instead
|
||||
SkASSERT(false);
|
||||
@ -198,7 +198,7 @@ void HCodeGenerator::writeMake() {
|
||||
fFullName.c_str());
|
||||
separator = "";
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
if (param->type() == *fContext.fTypes.fFragmentProcessor ||
|
||||
if (param->type().isFragmentProcessor() ||
|
||||
param->type().typeKind() == Type::TypeKind::kSampler) {
|
||||
this->writef("%sstd::move(%s)", separator, String(param->name()).c_str());
|
||||
} else {
|
||||
@ -257,7 +257,7 @@ void HCodeGenerator::writeConstructor() {
|
||||
}
|
||||
}
|
||||
this->writef(")");
|
||||
} else if (type == *fContext.fTypes.fFragmentProcessor) {
|
||||
} else if (type.isFragmentProcessor()) {
|
||||
// do nothing
|
||||
} else {
|
||||
this->writef("\n , %s(%s)", FieldName(name).c_str(), name);
|
||||
@ -275,7 +275,7 @@ void HCodeGenerator::writeConstructor() {
|
||||
const Type& paramType = param->type();
|
||||
if (paramType.typeKind() == Type::TypeKind::kSampler) {
|
||||
++samplerCount;
|
||||
} else if (paramType == *fContext.fTypes.fFragmentProcessor) {
|
||||
} else if (paramType.isFragmentProcessor()) {
|
||||
SampleUsage usage = Analysis::GetSampleUsage(fProgram, *param);
|
||||
|
||||
std::string perspExpression;
|
||||
@ -305,7 +305,7 @@ void HCodeGenerator::writeFields() {
|
||||
this->writeSection(kFieldsSection);
|
||||
for (const auto& param : fSectionAndParameterHelper.getParameters()) {
|
||||
String name = FieldName(String(param->name()).c_str());
|
||||
if (param->type() == *fContext.fTypes.fFragmentProcessor) {
|
||||
if (param->type().isFragmentProcessor()) {
|
||||
// Don't need to write any fields, FPs are held as children
|
||||
} else {
|
||||
this->writef(" %s %s;\n", FieldType(fContext, param->type(),
|
||||
|
@ -294,10 +294,8 @@ void IRGenerator::checkVarDeclaration(int offset, const Modifiers& modifiers, co
|
||||
}
|
||||
}
|
||||
if (this->programKind() == ProgramKind::kRuntimeEffect) {
|
||||
if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
|
||||
*baseType != *fContext.fTypes.fFragmentProcessor) {
|
||||
this->errorReporter().error(offset,
|
||||
"'in' variables not permitted in runtime effects");
|
||||
if ((modifiers.fFlags & Modifiers::kIn_Flag) && !baseType->isFragmentProcessor()) {
|
||||
this->errorReporter().error(offset, "'in' variables not permitted in runtime effects");
|
||||
}
|
||||
}
|
||||
if ((modifiers.fLayout.fFlags & Layout::kKey_Flag) &&
|
||||
@ -1047,7 +1045,7 @@ void IRGenerator::convertFunction(const ASTNode& f) {
|
||||
// Only the (builtin) declarations of 'sample' are allowed to have FP parameters.
|
||||
// (You can pass other opaque types to functions safely; this restriction is
|
||||
// fragment-processor specific.)
|
||||
if (*type == *fContext.fTypes.fFragmentProcessor && !fIsBuiltinCode) {
|
||||
if (type->isFragmentProcessor() && !fIsBuiltinCode) {
|
||||
this->errorReporter().error(
|
||||
param.fOffset, "parameters of type '" + type->displayName() + "' not allowed");
|
||||
return;
|
||||
@ -1524,7 +1522,7 @@ std::unique_ptr<Expression> IRGenerator::convertIdentifier(int offset, StringFra
|
||||
!(modifiers.fFlags & Modifiers::kUniform_Flag) &&
|
||||
!(modifiers.fLayout.fFlags & Layout::kKey_Flag) &&
|
||||
modifiers.fLayout.fBuiltin == -1 &&
|
||||
var->type() != *fContext.fTypes.fFragmentProcessor &&
|
||||
!var->type().isFragmentProcessor() &&
|
||||
var->type().typeKind() != Type::TypeKind::kSampler) {
|
||||
bool valid = false;
|
||||
for (const auto& decl : fFile->root()) {
|
||||
|
@ -145,7 +145,7 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
const ExpressionArray& arguments = c.arguments();
|
||||
if (function.isBuiltin() && function.name() == "sample") {
|
||||
SkASSERT(arguments.size() <= 2);
|
||||
SkASSERT("fragmentProcessor" == arguments[0]->type().name());
|
||||
SkASSERT(arguments[0]->type().isFragmentProcessor());
|
||||
SkASSERT(arguments[0]->is<VariableReference>());
|
||||
int index = 0;
|
||||
bool found = false;
|
||||
@ -155,7 +155,7 @@ void PipelineStageCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
const VarDeclaration& decl = global.declaration()->as<VarDeclaration>();
|
||||
if (&decl.var() == arguments[0]->as<VariableReference>().variable()) {
|
||||
found = true;
|
||||
} else if (decl.var().type() == *fProgram.fContext->fTypes.fFragmentProcessor) {
|
||||
} else if (decl.var().type().isFragmentProcessor()) {
|
||||
++index;
|
||||
}
|
||||
}
|
||||
@ -224,8 +224,7 @@ void PipelineStageCodeGenerator::writeVariableReference(const VariableReference&
|
||||
}
|
||||
// Skip over fragmentProcessors (shaders).
|
||||
// These are indexed separately from other globals.
|
||||
if (var.modifiers().fFlags & flag &&
|
||||
var.type() != *fProgram.fContext->fTypes.fFragmentProcessor) {
|
||||
if ((var.modifiers().fFlags & flag) && !var.type().isFragmentProcessor()) {
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
@ -332,6 +332,7 @@ static inline bool is_uniform(const SkSL::Variable& var) {
|
||||
|
||||
static size_t slot_count(const Type& type) {
|
||||
switch (type.typeKind()) {
|
||||
case Type::TypeKind::kFragmentProcessor:
|
||||
case Type::TypeKind::kOther:
|
||||
case Type::TypeKind::kVoid:
|
||||
return 0;
|
||||
@ -375,7 +376,7 @@ SkVMGenerator::SkVMGenerator(const Program& program,
|
||||
|
||||
// For most variables, fVariableMap stores an index into fSlots, but for fragment
|
||||
// processors (child shaders), fVariableMap stores the index to pass to fSampleChild().
|
||||
if (var.type() == *fProgram.fContext->fTypes.fFragmentProcessor) {
|
||||
if (var.type().isFragmentProcessor()) {
|
||||
fVariableMap[&var] = fpCount++;
|
||||
continue;
|
||||
}
|
||||
@ -1005,7 +1006,7 @@ Value SkVMGenerator::writeIntrinsicCall(const FunctionCall& c) {
|
||||
if (found->second == Intrinsic::kSample) {
|
||||
// Sample is very special, the first argument is an FP, which can't be evaluated
|
||||
const Context& ctx = *fProgram.fContext;
|
||||
if (nargs > 2 || c.arguments()[0]->type() != *ctx.fTypes.fFragmentProcessor ||
|
||||
if (nargs > 2 || !c.arguments()[0]->type().isFragmentProcessor() ||
|
||||
(nargs == 2 && (c.arguments()[1]->type() != *ctx.fTypes.fFloat2 &&
|
||||
c.arguments()[1]->type() != *ctx.fTypes.fFloat3x3))) {
|
||||
SkDEBUGFAIL("Invalid call to sample");
|
||||
@ -1815,7 +1816,7 @@ bool testingOnly_ProgramToSkVMShader(const Program& program, skvm::Builder* buil
|
||||
if (e->is<GlobalVarDeclaration>()) {
|
||||
const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
|
||||
const Variable& var = decl.declaration()->as<VarDeclaration>().var();
|
||||
if (var.type() == *program.fContext->fTypes.fFragmentProcessor) {
|
||||
if (var.type().isFragmentProcessor()) {
|
||||
childSlots++;
|
||||
} else if (is_uniform(var)) {
|
||||
uniformSlots += slot_count(var.type());
|
||||
|
@ -76,6 +76,7 @@ public:
|
||||
enum class TypeKind {
|
||||
kArray,
|
||||
kEnum,
|
||||
kFragmentProcessor,
|
||||
kGeneric,
|
||||
kMatrix,
|
||||
kOther,
|
||||
@ -216,11 +217,12 @@ public:
|
||||
*/
|
||||
bool isOpaque() const {
|
||||
switch (fTypeKind) {
|
||||
case TypeKind::kFragmentProcessor:
|
||||
case TypeKind::kOther:
|
||||
case TypeKind::kVoid:
|
||||
case TypeKind::kSampler:
|
||||
case TypeKind::kSeparateSampler:
|
||||
case TypeKind::kTexture:
|
||||
case TypeKind::kVoid:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -354,6 +356,10 @@ public:
|
||||
return fTypeKind == TypeKind::kEnum;
|
||||
}
|
||||
|
||||
bool isFragmentProcessor() const {
|
||||
return fTypeKind == TypeKind::kFragmentProcessor;
|
||||
}
|
||||
|
||||
bool isMultisampled() const {
|
||||
SkASSERT(TypeKind::kSampler == fTypeKind || TypeKind::kTexture == fTypeKind);
|
||||
return fIsMultisampled;
|
||||
@ -395,14 +401,15 @@ private:
|
||||
|
||||
using INHERITED = Symbol;
|
||||
|
||||
// Constructor for MakeOtherType.
|
||||
Type(const char* name)
|
||||
// Constructor for MakeFragmentProcessorType, MakeOtherType, MakeSeparateSamplerType,
|
||||
// and MakeVoidType.
|
||||
Type(const char* name, const char* abbrev, TypeKind kind)
|
||||
: INHERITED(-1, kSymbolKind, name)
|
||||
, fAbbreviatedName("O")
|
||||
, fTypeKind(TypeKind::kOther)
|
||||
, fAbbreviatedName(abbrev)
|
||||
, fTypeKind(kind)
|
||||
, fNumberKind(NumberKind::kNonnumeric) {}
|
||||
|
||||
// Constructor for MakeVoidType, MakeEnumType and MakeSeparateSamplerType.
|
||||
// Constructor for MakeEnumType.
|
||||
Type(String name, const char* abbrev, TypeKind kind)
|
||||
: INHERITED(-1, kSymbolKind, "")
|
||||
, fAbbreviatedName(abbrev)
|
||||
|
Loading…
Reference in New Issue
Block a user