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