blob: df74480765bfef28c415537b51c40fbf7a219d36 [file] [log] [blame]
/*
* Copyright 2021 Google LLC.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/sksl/DSLFunction.h"
#include "include/sksl/DSLVar.h"
#include "src/sksl/SkSLAnalysis.h"
#include "src/sksl/SkSLCompiler.h"
#include "src/sksl/SkSLIRGenerator.h"
#include "src/sksl/dsl/priv/DSLWriter.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
namespace SkSL {
namespace dsl {
void DSLFunction::init(const DSLType& returnType, const char* name,
std::vector<DSLVar*> params) {
std::vector<std::unique_ptr<Variable>> paramVars;
paramVars.reserve(params.size());
bool isMain = !strcmp(name, "main");
auto typeIsValidForColor = [&](const SkSL::Type& type) {
return type == *DSLWriter::Context().fTypes.fHalf4 ||
type == *DSLWriter::Context().fTypes.fFloat4;
};
for (DSLVar* param : params) {
// This counts as declaring the variable; make sure it hasn't been previously declared and
// then kill its pending declaration statement. Otherwise the statement will hang around
// until after the Var is destroyed, which is probably after the End() call and therefore
// after the Pool's destruction. Freeing a pooled object after the Pool's destruction is a
// Bad Thing.
if (param->fDeclared) {
DSLWriter::ReportError("error: using an already-declared variable as a function "
"parameter\n");
}
if (param->fInitialValue.release()) {
DSLWriter::ReportError("error: variables used as function parameters cannot have "
"initial values\n");
}
param->fDeclared = true;
param->fStorage = SkSL::VariableStorage::kParameter;
if (paramVars.empty()) {
SkSL::ProgramKind kind = DSLWriter::Context().fConfig->fKind;
if (isMain && (kind == ProgramKind::kRuntimeColorFilter ||
kind == ProgramKind::kRuntimeShader ||
kind == ProgramKind::kFragmentProcessor)) {
const SkSL::Type& type = param->fType.skslType();
// We verify that the signature is fully correct later. For now, if this is an .fp
// or runtime effect of any flavor, a float2 param is supposed to be the coords, and
// a half4/float parameter is supposed to be the input color:
if (type == *DSLWriter::Context().fTypes.fFloat2) {
param->fModifiers.fModifiers.fLayout.fBuiltin = SK_MAIN_COORDS_BUILTIN;
} else if (typeIsValidForColor(type)) {
param->fModifiers.fModifiers.fLayout.fBuiltin = SK_INPUT_COLOR_BUILTIN;
}
}
}
std::unique_ptr<SkSL::Variable> paramVar = DSLWriter::ParameterVar(*param);
SkASSERT(paramVar);
paramVars.push_back(std::move(paramVar));
param->fDeclaration = nullptr;
}
fDecl = SkSL::FunctionDeclaration::Convert(DSLWriter::Context(),
*DSLWriter::SymbolTable(),
*DSLWriter::IRGenerator().fModifiers, /*offset=*/-1,
DSLWriter::Modifiers(SkSL::Modifiers()),
isMain ? name : DSLWriter::Name(name),
std::move(paramVars), fReturnType,
/*isBuiltin=*/false);
}
void DSLFunction::define(DSLBlock block) {
if (!fDecl) {
return;
}
SkASSERTF(!fDecl->definition(), "function '%s' already defined", fDecl->description().c_str());
std::unique_ptr<Statement> body = block.release();
DSLWriter::IRGenerator().finalizeFunction(*fDecl, body.get());
auto function = std::make_unique<SkSL::FunctionDefinition>(/*offset=*/-1, fDecl,
/*builtin=*/false, std::move(body));
if (DSLWriter::Compiler().errorCount()) {
DSLWriter::ReportError(DSLWriter::Compiler().errorText(/*showCount=*/false).c_str());
DSLWriter::Compiler().setErrorCount(0);
SkASSERT(!DSLWriter::Compiler().errorCount());
}
fDecl->fDefinition = function.get();
DSLWriter::ProgramElements().push_back(std::move(function));
}
DSLExpression DSLFunction::call(SkTArray<DSLExpression> args) {
ExpressionArray released;
released.reserve_back(args.size());
for (DSLExpression& arg : args) {
released.push_back(arg.release());
}
return DSLWriter::Call(*fDecl, std::move(released));
}
} // namespace dsl
} // namespace SkSL