• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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 #ifndef SKSL_CONSTRUCTOR
9 #define SKSL_CONSTRUCTOR
10 
11 #include "src/sksl/SkSLIRGenerator.h"
12 #include "src/sksl/ir/SkSLExpression.h"
13 #include "src/sksl/ir/SkSLFloatLiteral.h"
14 #include "src/sksl/ir/SkSLIntLiteral.h"
15 #include "src/sksl/ir/SkSLPrefixExpression.h"
16 
17 namespace SkSL {
18 
19 /**
20  * Represents the construction of a compound type, such as "float2(x, y)".
21  *
22  * Vector constructors will always consist of either exactly 1 scalar, or a collection of vectors
23  * and scalars totalling exactly the right number of scalar components.
24  *
25  * Matrix constructors will always consist of either exactly 1 scalar, exactly 1 matrix, or a
26  * collection of vectors and scalars totalling exactly the right number of scalar components.
27  */
28 struct Constructor : public Expression {
ConstructorConstructor29     Constructor(int offset, const Type& type, std::vector<std::unique_ptr<Expression>> arguments)
30     : INHERITED(offset, kConstructor_Kind, type)
31     , fArguments(std::move(arguments)) {}
32 
constantPropagateConstructor33     std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
34                                                   const DefinitionMap& definitions) override {
35         if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind) {
36             if (fType.isFloat()) {
37                 // promote float(1) to 1.0
38                 int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue;
39                 return std::unique_ptr<Expression>(new FloatLiteral(irGenerator.fContext,
40                                                                     fOffset,
41                                                                     intValue));
42             } else if (fType.isInteger()) {
43                 // promote uint(1) to 1u
44                 int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue;
45                 return std::unique_ptr<Expression>(new IntLiteral(fOffset,
46                                                                   intValue,
47                                                                   &fType));
48             }
49         }
50         return nullptr;
51     }
52 
hasSideEffectsConstructor53     bool hasSideEffects() const override {
54         for (const auto& arg : fArguments) {
55             if (arg->hasSideEffects()) {
56                 return true;
57             }
58         }
59         return false;
60     }
61 
cloneConstructor62     std::unique_ptr<Expression> clone() const override {
63         std::vector<std::unique_ptr<Expression>> cloned;
64         for (const auto& arg : fArguments) {
65             cloned.push_back(arg->clone());
66         }
67         return std::unique_ptr<Expression>(new Constructor(fOffset, fType, std::move(cloned)));
68     }
69 
descriptionConstructor70     String description() const override {
71         String result = fType.description() + "(";
72         String separator;
73         for (size_t i = 0; i < fArguments.size(); i++) {
74             result += separator;
75             result += fArguments[i]->description();
76             separator = ", ";
77         }
78         result += ")";
79         return result;
80     }
81 
isConstantConstructor82     bool isConstant() const override {
83         for (size_t i = 0; i < fArguments.size(); i++) {
84             if (!fArguments[i]->isConstant()) {
85                 return false;
86             }
87         }
88         return true;
89     }
90 
compareConstantConstructor91     bool compareConstant(const Context& context, const Expression& other) const override {
92         SkASSERT(other.fKind == Expression::kConstructor_Kind && other.fType == fType);
93         Constructor& c = (Constructor&) other;
94         if (c.fType.kind() == Type::kVector_Kind) {
95             bool isFloat = c.fType.columns() > 1 ? c.fType.componentType().isFloat()
96                                                  : c.fType.isFloat();
97             for (int i = 0; i < fType.columns(); i++) {
98                 if (isFloat) {
99                     if (this->getFVecComponent(i) != c.getFVecComponent(i)) {
100                         return false;
101                     }
102                 } else if (this->getIVecComponent(i) != c.getIVecComponent(i)) {
103                     return false;
104                 }
105             }
106             return true;
107         }
108         // shouldn't be possible to have a constant constructor that isn't a vector or matrix;
109         // a constant scalar constructor should have been collapsed down to the appropriate
110         // literal
111         SkASSERT(fType.kind() == Type::kMatrix_Kind);
112         for (int col = 0; col < fType.columns(); col++) {
113             for (int row = 0; row < fType.rows(); row++) {
114                 if (getMatComponent(col, row) != c.getMatComponent(col, row)) {
115                     return false;
116                 }
117             }
118         }
119         return true;
120     }
121 
122     template<typename type>
getVecComponentConstructor123     type getVecComponent(int index) const {
124         SkASSERT(fType.kind() == Type::kVector_Kind);
125         if (fArguments.size() == 1 && fArguments[0]->fType.kind() == Type::kScalar_Kind) {
126             if (std::is_floating_point<type>::value) {
127                 return fArguments[0]->getConstantFloat();
128             } else {
129                 return fArguments[0]->getConstantInt();
130             }
131         }
132         int current = 0;
133         for (const auto& arg : fArguments) {
134             SkASSERT(current <= index);
135             if (arg->fType.kind() == Type::kScalar_Kind) {
136                 if (index == current) {
137                     if (std::is_floating_point<type>::value) {
138                         return arg.get()->getConstantFloat();
139                     } else {
140                         return arg.get()->getConstantInt();
141                     }
142                 }
143                 current++;
144             } else if (arg->fKind == kConstructor_Kind) {
145                 if (current + arg->fType.columns() > index) {
146                     return ((const Constructor&) *arg).getVecComponent<type>(index - current);
147                 }
148                 current += arg->fType.columns();
149             } else {
150                 if (current + arg->fType.columns() > index) {
151                     SkASSERT(arg->fKind == kPrefix_Kind);
152                     const PrefixExpression& p = (PrefixExpression&) *arg;
153                     const Constructor& c = (const Constructor&) *p.fOperand;
154                     return -c.getVecComponent<type>(index - current);
155                 }
156                 current += arg->fType.columns();
157             }
158         }
159         ABORT("failed to find vector component %d in %s\n", index, description().c_str());
160     }
161 
getFVecComponentConstructor162     SKSL_FLOAT getFVecComponent(int n) const override {
163         return this->getVecComponent<SKSL_FLOAT>(n);
164     }
165 
166     /**
167      * For a literal vector expression, return the integer value of the n'th vector component. It is
168      * an error to call this method on an expression which is not a literal vector.
169      */
getIVecComponentConstructor170     SKSL_INT getIVecComponent(int n) const override {
171         return this->getVecComponent<SKSL_INT>(n);
172     }
173 
getMatComponentConstructor174     SKSL_FLOAT getMatComponent(int col, int row) const override {
175         SkASSERT(this->isConstant());
176         SkASSERT(fType.kind() == Type::kMatrix_Kind);
177         SkASSERT(col < fType.columns() && row < fType.rows());
178         if (fArguments.size() == 1) {
179             if (fArguments[0]->fType.kind() == Type::kScalar_Kind) {
180                 // single scalar argument, so matrix is of the form:
181                 // x 0 0
182                 // 0 x 0
183                 // 0 0 x
184                 // return x if col == row
185                 return col == row ? fArguments[0]->getConstantFloat() : 0.0;
186             }
187             if (fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
188                 SkASSERT(fArguments[0]->fKind == Expression::kConstructor_Kind);
189                 // single matrix argument. make sure we're within the argument's bounds.
190                 const Type& argType = ((Constructor&) *fArguments[0]).fType;
191                 if (col < argType.columns() && row < argType.rows()) {
192                     // within bounds, defer to argument
193                     return ((Constructor&) *fArguments[0]).getMatComponent(col, row);
194                 }
195                 // out of bounds
196                 return 0.0;
197             }
198         }
199         int currentIndex = 0;
200         int targetIndex = col * fType.rows() + row;
201         for (const auto& arg : fArguments) {
202             SkASSERT(targetIndex >= currentIndex);
203             SkASSERT(arg->fType.rows() == 1);
204             if (currentIndex + arg->fType.columns() > targetIndex) {
205                 if (arg->fType.columns() == 1) {
206                     return arg->getConstantFloat();
207                 } else {
208                     return arg->getFVecComponent(targetIndex - currentIndex);
209                 }
210             }
211             currentIndex += arg->fType.columns();
212         }
213         ABORT("can't happen, matrix component out of bounds");
214     }
215 
216     std::vector<std::unique_ptr<Expression>> fArguments;
217 
218     typedef Expression INHERITED;
219 };
220 
221 } // namespace
222 
223 #endif
224