xref: /third_party/skia/src/sksl/dsl/DSLCore.cpp (revision cb93a386)
1/*
2 * Copyright 2020 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "include/sksl/DSLCore.h"
9
10#include "include/private/SkSLDefines.h"
11#include "include/sksl/DSLSymbols.h"
12#include "include/sksl/DSLVar.h"
13#include "src/sksl/SkSLCompiler.h"
14#include "src/sksl/SkSLThreadContext.h"
15#include "src/sksl/dsl/priv/DSLWriter.h"
16#include "src/sksl/ir/SkSLBlock.h"
17#include "src/sksl/ir/SkSLBreakStatement.h"
18#include "src/sksl/ir/SkSLContinueStatement.h"
19#include "src/sksl/ir/SkSLDiscardStatement.h"
20#include "src/sksl/ir/SkSLDoStatement.h"
21#include "src/sksl/ir/SkSLExtension.h"
22#include "src/sksl/ir/SkSLField.h"
23#include "src/sksl/ir/SkSLForStatement.h"
24#include "src/sksl/ir/SkSLFunctionCall.h"
25#include "src/sksl/ir/SkSLIfStatement.h"
26#include "src/sksl/ir/SkSLInterfaceBlock.h"
27#include "src/sksl/ir/SkSLModifiersDeclaration.h"
28#include "src/sksl/ir/SkSLReturnStatement.h"
29#include "src/sksl/ir/SkSLStructDefinition.h"
30#include "src/sksl/ir/SkSLSwitchStatement.h"
31#include "src/sksl/ir/SkSLSwizzle.h"
32#include "src/sksl/ir/SkSLTernaryExpression.h"
33#include "src/sksl/transform/SkSLTransform.h"
34
35namespace SkSL {
36
37namespace dsl {
38
39void Start(SkSL::Compiler* compiler, ProgramKind kind) {
40    Start(compiler, kind, ProgramSettings());
41}
42
43void Start(SkSL::Compiler* compiler, ProgramKind kind, const ProgramSettings& settings) {
44    ThreadContext::SetInstance(std::make_unique<ThreadContext>(compiler, kind, settings,
45            compiler->moduleForProgramKind(kind), /*isModule=*/false));
46}
47
48void StartModule(SkSL::Compiler* compiler, ProgramKind kind, const ProgramSettings& settings,
49                 SkSL::ParsedModule baseModule) {
50    ThreadContext::SetInstance(std::make_unique<ThreadContext>(compiler, kind, settings,
51            baseModule, /*isModule=*/true));
52}
53
54void End() {
55    SkASSERTF(!ThreadContext::InFragmentProcessor(),
56              "more calls to StartFragmentProcessor than to EndFragmentProcessor");
57    ThreadContext::SetInstance(nullptr);
58}
59
60ErrorReporter& GetErrorReporter() {
61    return ThreadContext::GetErrorReporter();
62}
63
64void SetErrorReporter(ErrorReporter* errorReporter) {
65    SkASSERT(errorReporter);
66    ThreadContext::SetErrorReporter(errorReporter);
67}
68
69class DSLCore {
70public:
71    static std::unique_ptr<SkSL::Program> ReleaseProgram(std::unique_ptr<String> source) {
72        ThreadContext& instance = ThreadContext::Instance();
73        SkSL::Compiler& compiler = *instance.fCompiler;
74        const SkSL::Context& context = *compiler.fContext;
75        // Variables defined in the pre-includes need their declaring elements added to the program
76        if (!instance.fConfig->fIsBuiltinCode && context.fIntrinsics) {
77            Transform::FindAndDeclareBuiltinVariables(context, instance.fConfig->fKind,
78                    instance.fSharedElements);
79        }
80        Pool* pool = instance.fPool.get();
81        auto result = std::make_unique<SkSL::Program>(std::move(source),
82                                                      std::move(instance.fConfig),
83                                                      compiler.fContext,
84                                                      std::move(instance.fProgramElements),
85                                                      std::move(instance.fSharedElements),
86                                                      std::move(instance.fModifiersPool),
87                                                      std::move(compiler.fSymbolTable),
88                                                      std::move(instance.fPool),
89                                                      instance.fInputs);
90        bool success = false;
91        if (!compiler.finalize(*result)) {
92            // Do not return programs that failed to compile.
93        } else if (!compiler.optimize(*result)) {
94            // Do not return programs that failed to optimize.
95        } else {
96            // We have a successful program!
97            success = true;
98        }
99        if (!success) {
100            ThreadContext::ReportErrors(PositionInfo());
101        }
102        if (pool) {
103            pool->detachFromThread();
104        }
105        SkASSERT(instance.fProgramElements.empty());
106        SkASSERT(!ThreadContext::SymbolTable());
107        return success ? std::move(result) : nullptr;
108    }
109
110    static DSLGlobalVar sk_FragColor() {
111        return DSLGlobalVar("sk_FragColor");
112    }
113
114    static DSLGlobalVar sk_FragCoord() {
115        return DSLGlobalVar("sk_FragCoord");
116    }
117
118    static DSLExpression sk_Position() {
119        return DSLExpression(Symbol("sk_Position"));
120    }
121
122    template <typename... Args>
123    static DSLPossibleExpression Call(const char* name, Args... args) {
124        SkSL::ExpressionArray argArray;
125        argArray.reserve_back(sizeof...(args));
126
127        // in C++17, we could just do:
128        // (argArray.push_back(args.release()), ...);
129        int unused[] = {0, (static_cast<void>(argArray.push_back(args.release())), 0)...};
130        static_cast<void>(unused);
131
132        return SkSL::FunctionCall::Convert(ThreadContext::Context(), /*line=*/-1,
133                ThreadContext::Compiler().convertIdentifier(-1, name), std::move(argArray));
134    }
135
136    static DSLStatement Break(PositionInfo pos) {
137        return SkSL::BreakStatement::Make(pos.line());
138    }
139
140    static DSLStatement Continue(PositionInfo pos) {
141        return SkSL::ContinueStatement::Make(pos.line());
142    }
143
144    static void Declare(const DSLModifiers& modifiers) {
145        ThreadContext::ProgramElements().push_back(std::make_unique<SkSL::ModifiersDeclaration>(
146                ThreadContext::Modifiers(modifiers.fModifiers)));
147    }
148
149    static DSLStatement Declare(DSLVar& var, PositionInfo pos) {
150        if (var.fDeclared) {
151            ThreadContext::ReportError("variable has already been declared", pos);
152        }
153        var.fDeclared = true;
154        return DSLWriter::Declaration(var);
155    }
156
157    static DSLStatement Declare(SkTArray<DSLVar>& vars, PositionInfo pos) {
158        StatementArray statements;
159        for (DSLVar& v : vars) {
160            statements.push_back(Declare(v, pos).release());
161        }
162        return SkSL::Block::MakeUnscoped(pos.line(), std::move(statements));
163    }
164
165    static void Declare(DSLGlobalVar& var, PositionInfo pos) {
166        if (var.fDeclared) {
167            ThreadContext::ReportError("variable has already been declared", pos);
168        }
169        var.fDeclared = true;
170        std::unique_ptr<SkSL::Statement> stmt = DSLWriter::Declaration(var);
171        if (stmt) {
172            if (!stmt->isEmpty()) {
173                ThreadContext::ProgramElements().push_back(
174                        std::make_unique<SkSL::GlobalVarDeclaration>(std::move(stmt)));
175            }
176        } else if (var.fName == SkSL::Compiler::FRAGCOLOR_NAME) {
177            // sk_FragColor can end up with a null declaration despite no error occurring due to
178            // specific treatment in the compiler. Ignore the null and just grab the existing
179            // variable from the symbol table.
180            const SkSL::Symbol* alreadyDeclared = (*ThreadContext::SymbolTable())[var.fName];
181            if (alreadyDeclared && alreadyDeclared->is<Variable>()) {
182                var.fVar = &alreadyDeclared->as<Variable>();
183                var.fInitialized = true;
184            }
185        }
186    }
187
188    static void Declare(SkTArray<DSLGlobalVar>& vars, PositionInfo pos) {
189        for (DSLGlobalVar& v : vars) {
190            Declare(v, pos);
191        }
192    }
193
194    static DSLStatement Discard(PositionInfo pos) {
195        return SkSL::DiscardStatement::Make(pos.line());
196    }
197
198    static DSLPossibleStatement Do(DSLStatement stmt, DSLExpression test) {
199        return DoStatement::Convert(ThreadContext::Context(), stmt.release(), test.release());
200    }
201
202    static DSLPossibleStatement For(DSLStatement initializer, DSLExpression test,
203                                    DSLExpression next, DSLStatement stmt, PositionInfo pos) {
204        return ForStatement::Convert(ThreadContext::Context(), pos.line(),
205                                     initializer.releaseIfPossible(), test.releaseIfPossible(),
206                                     next.releaseIfPossible(), stmt.release(),
207                                     ThreadContext::SymbolTable());
208    }
209
210    static DSLPossibleStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse,
211                                   bool isStatic) {
212        return IfStatement::Convert(ThreadContext::Context(), /*line=*/-1, isStatic, test.release(),
213                                    ifTrue.release(), ifFalse.releaseIfPossible());
214    }
215
216    static void FindRTAdjust(SkSL::InterfaceBlock& intf, PositionInfo pos) {
217        const std::vector<SkSL::Type::Field>& fields =
218                intf.variable().type().componentType().fields();
219        const Context& context = ThreadContext::Context();
220        for (size_t i = 0; i < fields.size(); ++i) {
221            const SkSL::Type::Field& f = fields[i];
222            if (f.fName == SkSL::Compiler::RTADJUST_NAME) {
223                if (*f.fType == *context.fTypes.fFloat4) {
224                    ThreadContext::RTAdjustData& rtAdjust = ThreadContext::RTAdjustState();
225                    rtAdjust.fInterfaceBlock = &intf.variable();
226                    rtAdjust.fFieldIndex = i;
227                } else {
228                    ThreadContext::ReportError("sk_RTAdjust must have type 'float4'", pos);
229                }
230                break;
231            }
232        }
233    }
234
235    static DSLGlobalVar InterfaceBlock(const DSLModifiers& modifiers, skstd::string_view typeName,
236                                       SkTArray<DSLField> fields, skstd::string_view varName,
237                                       int arraySize, PositionInfo pos) {
238        // We need to create a new struct type for the interface block, but we don't want it in the
239        // symbol table. Since dsl::Struct automatically sticks it in the symbol table, we create it
240        // the old fashioned way with MakeStructType.
241        std::vector<SkSL::Type::Field> skslFields;
242        skslFields.reserve(fields.count());
243        for (const DSLField& field : fields) {
244            const SkSL::Type* baseType = &field.fType.skslType();
245            if (baseType->isArray()) {
246                baseType = &baseType->componentType();
247            }
248            SkSL::VarDeclaration::ErrorCheck(ThreadContext::Context(), pos.line(),
249                    field.fModifiers.fModifiers, baseType, Variable::Storage::kInterfaceBlock);
250            GetErrorReporter().reportPendingErrors(field.fPosition);
251            skslFields.push_back(SkSL::Type::Field(field.fModifiers.fModifiers, field.fName,
252                                                   &field.fType.skslType()));
253        }
254        const SkSL::Type* structType = ThreadContext::SymbolTable()->takeOwnershipOfSymbol(
255                SkSL::Type::MakeStructType(pos.line(), typeName, std::move(skslFields)));
256        DSLType varType = arraySize > 0 ? Array(structType, arraySize) : DSLType(structType);
257        DSLGlobalVar var(modifiers, varType, !varName.empty() ? varName : typeName, DSLExpression(),
258                pos);
259        // Interface blocks can't be declared, so we always need to mark the var declared ourselves.
260        // We do this only when fDSLMarkVarDeclared is false, so we don't double-declare it.
261        if (!ThreadContext::Settings().fDSLMarkVarsDeclared) {
262            DSLWriter::MarkDeclared(var);
263        }
264        const SkSL::Variable* skslVar = DSLWriter::Var(var);
265        if (skslVar) {
266            auto intf = std::make_unique<SkSL::InterfaceBlock>(pos.line(),
267                    *skslVar, typeName, varName, arraySize, ThreadContext::SymbolTable());
268            FindRTAdjust(*intf, pos);
269            ThreadContext::ProgramElements().push_back(std::move(intf));
270            if (varName.empty()) {
271                const std::vector<SkSL::Type::Field>& structFields = structType->fields();
272                for (size_t i = 0; i < structFields.size(); ++i) {
273                    ThreadContext::SymbolTable()->add(std::make_unique<SkSL::Field>(pos.line(),
274                                                                                    skslVar,
275                                                                                    i));
276                }
277            } else {
278                AddToSymbolTable(var);
279            }
280        }
281        GetErrorReporter().reportPendingErrors(pos);
282        return var;
283    }
284
285    static DSLStatement Return(DSLExpression value, PositionInfo pos) {
286        // Note that because Return is called before the function in which it resides exists, at
287        // this point we do not know the function's return type. We therefore do not check for
288        // errors, or coerce the value to the correct type, until the return statement is actually
289        // added to a function. (This is done in FunctionDefinition::Convert.)
290        return SkSL::ReturnStatement::Make(pos.line(), value.releaseIfPossible());
291    }
292
293    static DSLExpression Swizzle(DSLExpression base, SkSL::SwizzleComponent::Type a,
294                                 PositionInfo pos) {
295        return DSLExpression(Swizzle::Convert(ThreadContext::Context(), base.release(),
296                                              ComponentArray{a}),
297                             pos);
298    }
299
300    static DSLExpression Swizzle(DSLExpression base,
301                                 SkSL::SwizzleComponent::Type a,
302                                 SkSL::SwizzleComponent::Type b,
303                                 PositionInfo pos) {
304        return DSLExpression(Swizzle::Convert(ThreadContext::Context(), base.release(),
305                                              ComponentArray{a, b}),
306                             pos);
307    }
308
309    static DSLExpression Swizzle(DSLExpression base,
310                                 SkSL::SwizzleComponent::Type a,
311                                 SkSL::SwizzleComponent::Type b,
312                                 SkSL::SwizzleComponent::Type c,
313                                 PositionInfo pos) {
314        return DSLExpression(Swizzle::Convert(ThreadContext::Context(), base.release(),
315                                              ComponentArray{a, b, c}),
316                             pos);
317    }
318
319    static DSLExpression Swizzle(DSLExpression base,
320                                 SkSL::SwizzleComponent::Type a,
321                                 SkSL::SwizzleComponent::Type b,
322                                 SkSL::SwizzleComponent::Type c,
323                                 SkSL::SwizzleComponent::Type d,
324                                 PositionInfo pos) {
325        return DSLExpression(Swizzle::Convert(ThreadContext::Context(), base.release(),
326                                              ComponentArray{a,b,c,d}),
327                             pos);
328    }
329
330    static DSLPossibleExpression Select(DSLExpression test, DSLExpression ifTrue,
331                                        DSLExpression ifFalse) {
332        return TernaryExpression::Convert(ThreadContext::Context(), test.release(),
333                                          ifTrue.release(), ifFalse.release());
334    }
335
336    static DSLPossibleStatement Switch(DSLExpression value, SkTArray<DSLCase> cases,
337                                       bool isStatic) {
338        ExpressionArray values;
339        values.reserve_back(cases.count());
340        StatementArray caseBlocks;
341        caseBlocks.reserve_back(cases.count());
342        for (DSLCase& c : cases) {
343            values.push_back(c.fValue.releaseIfPossible());
344            caseBlocks.push_back(SkSL::Block::Make(/*line=*/-1,
345                    std::move(c.fStatements), /*symbols=*/nullptr, /*isScope=*/false));
346        }
347        return SwitchStatement::Convert(ThreadContext::Context(), /*line=*/-1, isStatic,
348                value.release(), std::move(values), std::move(caseBlocks),
349                ThreadContext::SymbolTable());
350    }
351
352    static DSLPossibleStatement While(DSLExpression test, DSLStatement stmt) {
353        return ForStatement::ConvertWhile(ThreadContext::Context(), /*line=*/-1, test.release(),
354                                          stmt.release(), ThreadContext::SymbolTable());
355    }
356};
357
358std::unique_ptr<SkSL::Program> ReleaseProgram(std::unique_ptr<String> source) {
359    return DSLCore::ReleaseProgram(std::move(source));
360}
361
362DSLGlobalVar sk_FragColor() {
363    return DSLCore::sk_FragColor();
364}
365
366DSLGlobalVar sk_FragCoord() {
367    return DSLCore::sk_FragCoord();
368}
369
370DSLExpression sk_Position() {
371    return DSLCore::sk_Position();
372}
373
374void AddExtension(skstd::string_view name, PositionInfo pos) {
375    ThreadContext::ProgramElements().push_back(std::make_unique<SkSL::Extension>(pos.line(), name));
376    ThreadContext::ReportErrors(pos);
377}
378
379DSLStatement Break(PositionInfo pos) {
380    return DSLCore::Break(pos);
381}
382
383DSLStatement Continue(PositionInfo pos) {
384    return DSLCore::Continue(pos);
385}
386
387void Declare(const DSLModifiers& modifiers, PositionInfo pos) {
388    SkSL::ProgramKind kind = ThreadContext::GetProgramConfig()->fKind;
389    if (kind != ProgramKind::kFragment &&
390        kind != ProgramKind::kVertex) {
391        ThreadContext::ReportError("layout qualifiers are not allowed in this kind of program",
392                pos);
393        return;
394    }
395    DSLCore::Declare(modifiers);
396}
397
398// Logically, we'd want the variable's initial value to appear on here in Declare, since that
399// matches how we actually write code (and in fact that was what our first attempt looked like).
400// Unfortunately, C++ doesn't guarantee execution order between arguments, and Declare() can appear
401// as a function argument in constructs like Block(Declare(x, 0), foo(x)). If these are executed out
402// of order, we will evaluate the reference to x before we evaluate Declare(x, 0), and thus the
403// variable's initial value is unknown at the point of reference. There are probably some other
404// issues with this as well, but it is particularly dangerous when x is const, since SkSL will
405// expect its value to be known when it is referenced and will end up asserting, dereferencing a
406// null pointer, or possibly doing something else awful.
407//
408// So, we put the initial value onto the Var itself instead of the Declare to guarantee that it is
409// always executed in the correct order.
410DSLStatement Declare(DSLVar& var, PositionInfo pos) {
411    return DSLCore::Declare(var, pos);
412}
413
414DSLStatement Declare(SkTArray<DSLVar>& vars, PositionInfo pos) {
415    return DSLCore::Declare(vars, pos);
416}
417
418void Declare(DSLGlobalVar& var, PositionInfo pos) {
419    DSLCore::Declare(var, pos);
420}
421
422void Declare(SkTArray<DSLGlobalVar>& vars, PositionInfo pos) {
423    DSLCore::Declare(vars, pos);
424}
425
426DSLStatement Discard(PositionInfo pos) {
427    if (ThreadContext::GetProgramConfig()->fKind != ProgramKind::kFragment) {
428        ThreadContext::ReportError("discard statement is only permitted in fragment shaders", pos);
429    }
430    return DSLCore::Discard(pos);
431}
432
433DSLStatement Do(DSLStatement stmt, DSLExpression test, PositionInfo pos) {
434    return DSLStatement(DSLCore::Do(std::move(stmt), std::move(test)), pos);
435}
436
437DSLStatement For(DSLStatement initializer, DSLExpression test, DSLExpression next,
438                 DSLStatement stmt, PositionInfo pos) {
439    return DSLStatement(DSLCore::For(std::move(initializer), std::move(test), std::move(next),
440                                     std::move(stmt), pos), pos);
441}
442
443DSLStatement If(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse, PositionInfo pos) {
444    return DSLStatement(DSLCore::If(std::move(test), std::move(ifTrue), std::move(ifFalse),
445                                    /*isStatic=*/false),
446                        pos);
447}
448
449DSLGlobalVar InterfaceBlock(const DSLModifiers& modifiers,  skstd::string_view typeName,
450                            SkTArray<DSLField> fields, skstd::string_view varName, int arraySize,
451                            PositionInfo pos) {
452    SkSL::ProgramKind kind = ThreadContext::GetProgramConfig()->fKind;
453    if (kind != ProgramKind::kFragment &&
454        kind != ProgramKind::kVertex) {
455        ThreadContext::ReportError("interface blocks are not allowed in this kind of program", pos);
456        return DSLGlobalVar();
457    }
458    return DSLCore::InterfaceBlock(modifiers, typeName, std::move(fields), varName, arraySize, pos);
459}
460
461DSLStatement Return(DSLExpression expr, PositionInfo pos) {
462    return DSLCore::Return(std::move(expr), pos);
463}
464
465DSLExpression Select(DSLExpression test, DSLExpression ifTrue, DSLExpression ifFalse,
466                     PositionInfo pos) {
467    return DSLExpression(DSLCore::Select(std::move(test), std::move(ifTrue), std::move(ifFalse)),
468                         pos);
469}
470
471DSLStatement StaticIf(DSLExpression test, DSLStatement ifTrue, DSLStatement ifFalse,
472                      PositionInfo pos) {
473    return DSLStatement(DSLCore::If(std::move(test), std::move(ifTrue), std::move(ifFalse),
474                                    /*isStatic=*/true),
475                         pos);
476}
477
478DSLPossibleStatement PossibleStaticSwitch(DSLExpression value, SkTArray<DSLCase> cases) {
479    return DSLCore::Switch(std::move(value), std::move(cases), /*isStatic=*/true);
480}
481
482DSLStatement StaticSwitch(DSLExpression value, SkTArray<DSLCase> cases, PositionInfo pos) {
483    return DSLStatement(PossibleStaticSwitch(std::move(value), std::move(cases)), pos);
484}
485
486DSLPossibleStatement PossibleSwitch(DSLExpression value, SkTArray<DSLCase> cases) {
487    return DSLCore::Switch(std::move(value), std::move(cases), /*isStatic=*/false);
488}
489
490DSLStatement Switch(DSLExpression value, SkTArray<DSLCase> cases, PositionInfo pos) {
491    return DSLStatement(PossibleSwitch(std::move(value), std::move(cases)), pos);
492}
493
494DSLStatement While(DSLExpression test, DSLStatement stmt, PositionInfo pos) {
495    return DSLStatement(DSLCore::While(std::move(test), std::move(stmt)), pos);
496}
497
498DSLExpression Abs(DSLExpression x, PositionInfo pos) {
499    return DSLExpression(DSLCore::Call("abs", std::move(x)), pos);
500}
501
502DSLExpression All(DSLExpression x, PositionInfo pos) {
503    return DSLExpression(DSLCore::Call("all", std::move(x)), pos);
504}
505
506DSLExpression Any(DSLExpression x, PositionInfo pos) {
507    return DSLExpression(DSLCore::Call("any", std::move(x)), pos);
508}
509
510DSLExpression Atan(DSLExpression y_over_x, PositionInfo pos) {
511    return DSLExpression(DSLCore::Call("atan", std::move(y_over_x)), pos);
512}
513
514DSLExpression Atan(DSLExpression y, DSLExpression x, PositionInfo pos) {
515    return DSLExpression(DSLCore::Call("atan", std::move(y), std::move(x)), pos);
516}
517
518DSLExpression Ceil(DSLExpression x, PositionInfo pos) {
519    return DSLExpression(DSLCore::Call("ceil", std::move(x)), pos);
520}
521
522DSLExpression Clamp(DSLExpression x, DSLExpression min, DSLExpression max, PositionInfo pos) {
523    return DSLExpression(DSLCore::Call("clamp", std::move(x), std::move(min), std::move(max)), pos);
524}
525
526DSLExpression Cos(DSLExpression x, PositionInfo pos) {
527    return DSLExpression(DSLCore::Call("cos", std::move(x)), pos);
528}
529
530DSLExpression Cross(DSLExpression x, DSLExpression y, PositionInfo pos) {
531    return DSLExpression(DSLCore::Call("cross", std::move(x), std::move(y)), pos);
532}
533
534DSLExpression Degrees(DSLExpression x, PositionInfo pos) {
535    return DSLExpression(DSLCore::Call("degrees", std::move(x)), pos);
536}
537
538DSLExpression Distance(DSLExpression x, DSLExpression y, PositionInfo pos) {
539    return DSLExpression(DSLCore::Call("distance", std::move(x), std::move(y)), pos);
540}
541
542DSLExpression Dot(DSLExpression x, DSLExpression y, PositionInfo pos) {
543    return DSLExpression(DSLCore::Call("dot", std::move(x), std::move(y)), pos);
544}
545
546DSLExpression Equal(DSLExpression x, DSLExpression y, PositionInfo pos) {
547    return DSLExpression(DSLCore::Call("equal", std::move(x), std::move(y)), pos);
548}
549
550DSLExpression Exp(DSLExpression x, PositionInfo pos) {
551    return DSLExpression(DSLCore::Call("exp", std::move(x)), pos);
552}
553
554DSLExpression Exp2(DSLExpression x, PositionInfo pos) {
555    return DSLExpression(DSLCore::Call("exp2", std::move(x)), pos);
556}
557
558DSLExpression Faceforward(DSLExpression n, DSLExpression i, DSLExpression nref, PositionInfo pos) {
559    return DSLExpression(DSLCore::Call("faceforward", std::move(n), std::move(i), std::move(nref)),
560                         pos);
561}
562
563DSLExpression Fract(DSLExpression x, PositionInfo pos) {
564    return DSLExpression(DSLCore::Call("fract", std::move(x)), pos);
565}
566
567DSLExpression Floor(DSLExpression x, PositionInfo pos) {
568    return DSLExpression(DSLCore::Call("floor", std::move(x)), pos);
569}
570
571DSLExpression GreaterThan(DSLExpression x, DSLExpression y, PositionInfo pos) {
572    return DSLExpression(DSLCore::Call("greaterThan", std::move(x), std::move(y)), pos);
573}
574
575DSLExpression GreaterThanEqual(DSLExpression x, DSLExpression y, PositionInfo pos) {
576    return DSLExpression(DSLCore::Call("greaterThanEqual", std::move(x), std::move(y)), pos);
577}
578
579DSLExpression Inverse(DSLExpression x, PositionInfo pos) {
580    return DSLExpression(DSLCore::Call("inverse", std::move(x)), pos);
581}
582
583DSLExpression Inversesqrt(DSLExpression x, PositionInfo pos) {
584    return DSLExpression(DSLCore::Call("inversesqrt", std::move(x)), pos);
585}
586
587DSLExpression Length(DSLExpression x, PositionInfo pos) {
588    return DSLExpression(DSLCore::Call("length", std::move(x)), pos);
589}
590
591DSLExpression LessThan(DSLExpression x, DSLExpression y, PositionInfo pos) {
592    return DSLExpression(DSLCore::Call("lessThan", std::move(x), std::move(y)), pos);
593}
594
595DSLExpression LessThanEqual(DSLExpression x, DSLExpression y, PositionInfo pos) {
596    return DSLExpression(DSLCore::Call("lessThanEqual", std::move(x), std::move(y)), pos);
597}
598
599DSLExpression Log(DSLExpression x, PositionInfo pos) {
600    return DSLExpression(DSLCore::Call("log", std::move(x)), pos);
601}
602
603DSLExpression Log2(DSLExpression x, PositionInfo pos) {
604    return DSLExpression(DSLCore::Call("log2", std::move(x)), pos);
605}
606
607DSLExpression Max(DSLExpression x, DSLExpression y, PositionInfo pos) {
608    return DSLExpression(DSLCore::Call("max", std::move(x), std::move(y)), pos);
609}
610
611DSLExpression Min(DSLExpression x, DSLExpression y, PositionInfo pos) {
612    return DSLExpression(DSLCore::Call("min", std::move(x), std::move(y)), pos);
613}
614
615DSLExpression Mix(DSLExpression x, DSLExpression y, DSLExpression a, PositionInfo pos) {
616    return DSLExpression(DSLCore::Call("mix", std::move(x), std::move(y), std::move(a)), pos);
617}
618
619DSLExpression Mod(DSLExpression x, DSLExpression y, PositionInfo pos) {
620    return DSLExpression(DSLCore::Call("mod", std::move(x), std::move(y)), pos);
621}
622
623DSLExpression Normalize(DSLExpression x, PositionInfo pos) {
624    return DSLExpression(DSLCore::Call("normalize", std::move(x)), pos);
625}
626
627DSLExpression NotEqual(DSLExpression x, DSLExpression y, PositionInfo pos) {
628    return DSLExpression(DSLCore::Call("notEqual", std::move(x), std::move(y)), pos);
629}
630
631DSLExpression Pow(DSLExpression x, DSLExpression y, PositionInfo pos) {
632    return DSLExpression(DSLCore::Call("pow", std::move(x), std::move(y)), pos);
633}
634
635DSLExpression Radians(DSLExpression x, PositionInfo pos) {
636    return DSLExpression(DSLCore::Call("radians", std::move(x)), pos);
637}
638
639DSLExpression Reflect(DSLExpression i, DSLExpression n, PositionInfo pos) {
640    return DSLExpression(DSLCore::Call("reflect", std::move(i), std::move(n)), pos);
641}
642
643DSLExpression Refract(DSLExpression i, DSLExpression n, DSLExpression eta, PositionInfo pos) {
644    return DSLExpression(DSLCore::Call("refract", std::move(i), std::move(n), std::move(eta)), pos);
645}
646
647DSLExpression Round(DSLExpression x, PositionInfo pos) {
648    return DSLExpression(DSLCore::Call("round", std::move(x)), pos);
649}
650
651DSLExpression Saturate(DSLExpression x, PositionInfo pos) {
652    return DSLExpression(DSLCore::Call("saturate", std::move(x)), pos);
653}
654
655DSLExpression Sign(DSLExpression x, PositionInfo pos) {
656    return DSLExpression(DSLCore::Call("sign", std::move(x)), pos);
657}
658
659DSLExpression Sin(DSLExpression x, PositionInfo pos) {
660    return DSLExpression(DSLCore::Call("sin", std::move(x)), pos);
661}
662
663DSLExpression Smoothstep(DSLExpression edge1, DSLExpression edge2, DSLExpression x,
664                         PositionInfo pos) {
665    return DSLExpression(DSLCore::Call("smoothstep", std::move(edge1), std::move(edge2),
666                                       std::move(x)),
667                         pos);
668}
669
670DSLExpression Sqrt(DSLExpression x, PositionInfo pos) {
671    return DSLExpression(DSLCore::Call("sqrt", std::move(x)), pos);
672}
673
674DSLExpression Step(DSLExpression edge, DSLExpression x, PositionInfo pos) {
675    return DSLExpression(DSLCore::Call("step", std::move(edge), std::move(x)), pos);
676}
677
678DSLExpression Swizzle(DSLExpression base, SkSL::SwizzleComponent::Type a,
679                      PositionInfo pos) {
680    return DSLCore::Swizzle(std::move(base), a, pos);
681}
682
683DSLExpression Swizzle(DSLExpression base,
684                      SkSL::SwizzleComponent::Type a,
685                      SkSL::SwizzleComponent::Type b,
686                      PositionInfo pos) {
687    return DSLCore::Swizzle(std::move(base), a, b, pos);
688}
689
690DSLExpression Swizzle(DSLExpression base,
691                      SkSL::SwizzleComponent::Type a,
692                      SkSL::SwizzleComponent::Type b,
693                      SkSL::SwizzleComponent::Type c,
694                      PositionInfo pos) {
695    return DSLCore::Swizzle(std::move(base), a, b, c, pos);
696}
697
698DSLExpression Swizzle(DSLExpression base,
699                      SkSL::SwizzleComponent::Type a,
700                      SkSL::SwizzleComponent::Type b,
701                      SkSL::SwizzleComponent::Type c,
702                      SkSL::SwizzleComponent::Type d,
703                      PositionInfo pos) {
704    return DSLCore::Swizzle(std::move(base), a, b, c, d, pos);
705}
706
707DSLExpression Tan(DSLExpression x, PositionInfo pos) {
708    return DSLExpression(DSLCore::Call("tan", std::move(x)), pos);
709}
710
711DSLExpression Unpremul(DSLExpression x, PositionInfo pos) {
712    return DSLExpression(DSLCore::Call("unpremul", std::move(x)), pos);
713}
714
715} // namespace dsl
716
717} // namespace SkSL
718