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 "src/sksl/dsl/priv/DSLWriter.h"
9
10 #include "include/core/SkTypes.h"
11 #include "include/private/SkSLDefines.h"
12 #include "include/private/SkSLProgramElement.h"
13 #include "include/private/SkSLStatement.h"
14 #include "include/sksl/DSLCore.h"
15 #include "include/sksl/DSLExpression.h"
16 #include "include/sksl/DSLModifiers.h"
17 #include "include/sksl/DSLStatement.h"
18 #include "include/sksl/DSLType.h"
19 #include "include/sksl/DSLVar.h"
20 #include "include/sksl/SkSLPosition.h"
21 #include "src/sksl/SkSLModifiersPool.h"
22 #include "src/sksl/SkSLThreadContext.h"
23 #include "src/sksl/ir/SkSLBlock.h"
24 #include "src/sksl/ir/SkSLExpression.h"
25 #include "src/sksl/ir/SkSLNop.h"
26 #include "src/sksl/ir/SkSLSymbolTable.h"
27 #include "src/sksl/ir/SkSLType.h"
28 #include "src/sksl/ir/SkSLVarDeclarations.h"
29 #include "src/sksl/ir/SkSLVariable.h"
30
31 #include <utility>
32 #include <vector>
33
34 namespace SkSL {
35
36 namespace dsl {
37
Var(DSLVarBase & var)38 SkSL::Variable* DSLWriter::Var(DSLVarBase& var) {
39 // fInitialized is true if we have attempted to create a var, whether or not we actually
40 // succeeded. If it's true, we don't want to try again, to avoid reporting the same error
41 // multiple times.
42 if (!var.fInitialized) {
43 // We haven't even attempted to create a var yet, so fVar ought to be null
44 SkASSERT(!var.fVar);
45 var.fInitialized = true;
46 if (var.storage() != SkSL::VariableStorage::kParameter) {
47 const SkSL::Type* baseType = &var.fType.skslType();
48 if (baseType->isArray()) {
49 baseType = &baseType->componentType();
50 }
51 }
52 std::unique_ptr<SkSL::Variable> skslvar = SkSL::Variable::Convert(ThreadContext::Context(),
53 var.fPosition,
54 var.fModifiers.fPosition,
55 var.fModifiers.fModifiers,
56 &var.fType.skslType(),
57 var.fNamePosition,
58 var.fName,
59 /*isArray=*/false,
60 /*arraySize=*/nullptr,
61 var.storage());
62 SkSL::Variable* varPtr = skslvar.get();
63 if (var.storage() != SkSL::VariableStorage::kParameter) {
64 var.fDeclaration = VarDeclaration::Convert(ThreadContext::Context(),
65 std::move(skslvar),
66 var.fInitialValue.releaseIfPossible(),
67 /*addToSymbolTable=*/false);
68 if (var.fDeclaration) {
69 var.fVar = varPtr;
70 var.fInitialized = true;
71 }
72 }
73 }
74 return var.fVar;
75 }
76
CreateParameterVar(DSLParameter & var)77 std::unique_ptr<SkSL::Variable> DSLWriter::CreateParameterVar(DSLParameter& var) {
78 // This should only be called on undeclared parameter variables, but we allow the creation to go
79 // ahead regardless so we don't have to worry about null pointers potentially sneaking in and
80 // breaking things. DSLFunction is responsible for reporting errors for invalid parameters.
81 return SkSL::Variable::Convert(ThreadContext::Context(),
82 var.fPosition,
83 var.fModifiers.fPosition,
84 var.fModifiers.fModifiers,
85 &var.fType.skslType(),
86 var.fNamePosition,
87 var.fName,
88 /*isArray=*/false,
89 /*arraySize=*/nullptr,
90 var.storage());
91 }
92
Declaration(DSLVarBase & var)93 std::unique_ptr<SkSL::Statement> DSLWriter::Declaration(DSLVarBase& var) {
94 Var(var);
95 if (!var.fDeclaration) {
96 // We should have already reported an error before ending up here, just clean up the
97 // initial value so it doesn't assert and return a nop.
98 var.fInitialValue.releaseIfPossible();
99 return SkSL::Nop::Make();
100 }
101 return std::move(var.fDeclaration);
102 }
103
AddVarDeclaration(DSLStatement & existing,DSLVar & additional)104 void DSLWriter::AddVarDeclaration(DSLStatement& existing, DSLVar& additional) {
105 if (existing.fStatement->is<Block>()) {
106 SkSL::Block& block = existing.fStatement->as<Block>();
107 SkASSERT(!block.isScope());
108 block.children().push_back(Declare(additional).release());
109 } else if (existing.fStatement->is<VarDeclaration>()) {
110 Position pos = existing.fStatement->fPosition;
111 StatementArray stmts;
112 stmts.reserve_back(2);
113 stmts.push_back(std::move(existing.fStatement));
114 stmts.push_back(Declare(additional).release());
115 existing.fStatement = SkSL::Block::Make(pos, std::move(stmts),
116 Block::Kind::kCompoundStatement);
117 } else if (existing.fStatement->isEmpty()) {
118 // If the variable declaration generated an error, we can end up with a Nop statement here.
119 existing.fStatement = Declare(additional).release();
120 }
121 }
122
Reset()123 void DSLWriter::Reset() {
124 SymbolTable::Pop(&ThreadContext::SymbolTable());
125 SymbolTable::Push(&ThreadContext::SymbolTable());
126 ThreadContext::ProgramElements().clear();
127 ThreadContext::GetModifiersPool()->clear();
128 }
129
130 } // namespace dsl
131
132 } // namespace SkSL
133