| /* |
| * 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<const 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::kRuntimeEffect || |
| 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; |
| } |
| } |
| } |
| paramVars.push_back(&DSLWriter::Var(*param)); |
| param->fDeclaration = nullptr; |
| } |
| SkSL::SymbolTable& symbols = *DSLWriter::SymbolTable(); |
| fDecl = symbols.add(std::make_unique<SkSL::FunctionDeclaration>( |
| /*offset=*/-1, |
| DSLWriter::Modifiers(SkSL::Modifiers()), |
| isMain ? name : DSLWriter::Name(name), |
| std::move(paramVars), fReturnType, |
| /*builtin=*/false)); |
| } |
| |
| void DSLFunction::define(DSLBlock block) { |
| SkASSERT(fDecl); |
| 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 |