xref: /third_party/skia/src/sksl/dsl/DSLVar.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/DSLVar.h"
9
10#include "include/sksl/DSLModifiers.h"
11#include "include/sksl/DSLType.h"
12#include "src/sksl/SkSLCompiler.h"
13#include "src/sksl/SkSLThreadContext.h"
14#include "src/sksl/SkSLUtil.h"
15#include "src/sksl/dsl/priv/DSLWriter.h"
16#include "src/sksl/ir/SkSLBinaryExpression.h"
17#include "src/sksl/ir/SkSLFunctionCall.h"
18#include "src/sksl/ir/SkSLSymbolTable.h"
19#include "src/sksl/ir/SkSLVariable.h"
20#include "src/sksl/ir/SkSLVariableReference.h"
21
22namespace SkSL {
23
24namespace dsl {
25
26DSLVarBase::DSLVarBase(DSLType type, skstd::string_view name, DSLExpression initialValue,
27                       PositionInfo pos)
28    : DSLVarBase(DSLModifiers(), std::move(type), name, std::move(initialValue), pos) {}
29
30DSLVarBase::DSLVarBase(DSLType type, DSLExpression initialValue, PositionInfo pos)
31    : DSLVarBase(type, "var", std::move(initialValue), pos) {}
32
33DSLVarBase::DSLVarBase(const DSLModifiers& modifiers, DSLType type, DSLExpression initialValue,
34                       PositionInfo pos)
35    : DSLVarBase(modifiers, type, "var", std::move(initialValue), pos) {}
36
37DSLVarBase::DSLVarBase(const DSLModifiers& modifiers, DSLType type, skstd::string_view name,
38                       DSLExpression initialValue, PositionInfo pos)
39    : fModifiers(std::move(modifiers))
40    , fType(std::move(type))
41    , fRawName(name)
42    , fName(fType.skslType().isOpaque() ? name : DSLWriter::Name(name))
43    , fInitialValue(std::move(initialValue))
44    , fDeclared(DSLWriter::MarkVarsDeclared())
45    , fPosition(pos) {
46    if (fModifiers.fModifiers.fFlags & Modifiers::kUniform_Flag) {
47#if SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)
48        if (ThreadContext::InFragmentProcessor()) {
49            const SkSL::Type& skslType = type.skslType();
50            GrSLType grslType;
51            int count;
52            if (skslType.isArray()) {
53                SkAssertResult(SkSL::type_to_grsltype(ThreadContext::Context(),
54                        skslType.componentType(), &grslType));
55                count = skslType.columns();
56                SkASSERT(count > 0);
57            } else {
58                SkAssertResult(SkSL::type_to_grsltype(ThreadContext::Context(), skslType,
59                        &grslType));
60                count = 0;
61            }
62            const char* uniformName;
63            SkASSERT(ThreadContext::CurrentEmitArgs());
64            fUniformHandle = ThreadContext::CurrentEmitArgs()->fUniformHandler->addUniformArray(
65                    &ThreadContext::CurrentEmitArgs()->fFp, kFragment_GrShaderFlag, grslType,
66                    String(this->name()).c_str(), count, &uniformName).toIndex();
67            fName = uniformName;
68        }
69#endif // SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)
70    }
71}
72
73DSLVarBase::~DSLVarBase() {
74    if (fDeclaration && !fDeclared) {
75        ThreadContext::ReportError(String::printf("variable '%.*s' was destroyed without being "
76                                                  "declared",
77                                                  (int)fRawName.length(),
78                                                  fRawName.data()).c_str());
79    }
80}
81
82void DSLVarBase::swap(DSLVarBase& other) {
83    SkASSERT(this->storage() == other.storage());
84    std::swap(fModifiers, other.fModifiers);
85    std::swap(fType, other.fType);
86    std::swap(fUniformHandle, other.fUniformHandle);
87    std::swap(fDeclaration, other.fDeclaration);
88    std::swap(fVar, other.fVar);
89    std::swap(fRawName, other.fRawName);
90    std::swap(fName, other.fName);
91    std::swap(fInitialValue.fExpression, other.fInitialValue.fExpression);
92    std::swap(fDeclared, other.fDeclared);
93    std::swap(fInitialized, other.fInitialized);
94    std::swap(fPosition, other.fPosition);
95}
96
97void DSLVar::swap(DSLVar& other) {
98    INHERITED::swap(other);
99}
100
101VariableStorage DSLVar::storage() const {
102    return VariableStorage::kLocal;
103}
104
105DSLGlobalVar::DSLGlobalVar(const char* name)
106    : INHERITED(kVoid_Type, name, DSLExpression(), PositionInfo()) {
107    fName = name;
108    DSLWriter::MarkDeclared(*this);
109#if SK_SUPPORT_GPU && !defined(SKSL_STANDALONE)
110    if (!strcmp(name, "sk_SampleCoord")) {
111        fName = ThreadContext::CurrentEmitArgs()->fSampleCoord;
112        // The actual sk_SampleCoord variable hasn't been created by GrGLSLFPFragmentBuilder yet, so
113        // if we attempt to look it up in the symbol table we'll get null. As we are currently
114        // converting all DSL code into strings rather than nodes, all we really need is a
115        // correctly-named variable with the right type, so we just create a placeholder for it.
116        // TODO(skia/11330): we'll need to fix this when switching over to nodes.
117        const SkSL::Modifiers* modifiers = ThreadContext::Context().fModifiersPool->add(
118                SkSL::Modifiers(SkSL::Layout(/*flags=*/0, /*location=*/-1, /*offset=*/-1,
119                                             /*binding=*/-1, /*index=*/-1, /*set=*/-1,
120                                             SK_MAIN_COORDS_BUILTIN, /*inputAttachmentIndex=*/-1),
121                                SkSL::Modifiers::kNo_Flag));
122
123        fVar = ThreadContext::SymbolTable()->takeOwnershipOfIRNode(std::make_unique<SkSL::Variable>(
124                /*line=*/-1,
125                modifiers,
126                fName,
127                ThreadContext::Context().fTypes.fFloat2.get(),
128                /*builtin=*/true,
129                SkSL::VariableStorage::kGlobal));
130        fInitialized = true;
131        return;
132    }
133#endif
134    const SkSL::Symbol* result = (*ThreadContext::SymbolTable())[fName];
135    SkASSERTF(result, "could not find '%.*s' in symbol table", (int)fName.length(), fName.data());
136    fVar = &result->as<SkSL::Variable>();
137    fInitialized = true;
138}
139
140void DSLGlobalVar::swap(DSLGlobalVar& other) {
141    INHERITED::swap(other);
142}
143
144VariableStorage DSLGlobalVar::storage() const {
145    return VariableStorage::kGlobal;
146}
147
148void DSLParameter::swap(DSLParameter& other) {
149    INHERITED::swap(other);
150}
151
152VariableStorage DSLParameter::storage() const {
153    return VariableStorage::kParameter;
154}
155
156
157DSLPossibleExpression DSLVarBase::operator[](DSLExpression&& index) {
158    return DSLExpression(*this, PositionInfo())[std::move(index)];
159}
160
161DSLPossibleExpression DSLVarBase::assign(DSLExpression expr) {
162    return BinaryExpression::Convert(ThreadContext::Context(),
163            DSLExpression(*this, PositionInfo()).release(), SkSL::Token::Kind::TK_EQ,
164            expr.release());
165}
166
167DSLPossibleExpression DSLVar::operator=(DSLExpression expr) {
168    return this->assign(std::move(expr));
169}
170
171DSLPossibleExpression DSLGlobalVar::operator=(DSLExpression expr) {
172    return this->assign(std::move(expr));
173}
174
175DSLPossibleExpression DSLParameter::operator=(DSLExpression expr) {
176    return this->assign(std::move(expr));
177}
178
179std::unique_ptr<SkSL::Expression> DSLGlobalVar::methodCall(skstd::string_view methodName,
180                                                           PositionInfo pos) {
181    if (!this->fType.isEffectChild()) {
182        ThreadContext::ReportError("type does not support method calls", pos);
183        return nullptr;
184    }
185    return FieldAccess::Convert(ThreadContext::Context(), *ThreadContext::SymbolTable(),
186            DSLExpression(*this, PositionInfo()).release(), methodName);
187}
188
189DSLExpression DSLGlobalVar::eval(ExpressionArray args, PositionInfo pos) {
190    auto method = this->methodCall("eval", pos);
191    return DSLExpression(
192            method ? SkSL::FunctionCall::Convert(ThreadContext::Context(), pos.line(),
193                                                 std::move(method), std::move(args))
194                   : nullptr,
195            pos);
196}
197
198DSLExpression DSLGlobalVar::eval(DSLExpression x, PositionInfo pos) {
199    ExpressionArray converted;
200    converted.push_back(x.release());
201    return this->eval(std::move(converted), pos);
202}
203
204DSLExpression DSLGlobalVar::eval(DSLExpression x, DSLExpression y, PositionInfo pos) {
205    ExpressionArray converted;
206    converted.push_back(x.release());
207    converted.push_back(y.release());
208    return this->eval(std::move(converted), pos);
209}
210
211} // namespace dsl
212
213} // namespace SkSL
214