blob: beed0f702d906b8dd1c9db4197b011edb9e1c573 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
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 */
Greg Daniel64773e62016-11-22 09:44:03 -05007
ethannicholasb3058bd2016-07-01 08:22:01 -07008#ifndef SKSL_CONSTRUCTOR
9#define SKSL_CONSTRUCTOR
10
11#include "SkSLExpression.h"
Ethan Nicholas86a43402017-01-19 13:32:00 -050012#include "SkSLFloatLiteral.h"
13#include "SkSLIntLiteral.h"
14#include "SkSLIRGenerator.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070015
16namespace SkSL {
17
18/**
Ethan Nicholas5af9ea32017-07-28 15:19:46 -040019 * Represents the construction of a compound type, such as "float2x, y)".
Ethan Nicholas84645e32017-02-09 13:57:14 -050020 *
21 * Vector constructors will always consist of either exactly 1 scalar, or a collection of vectors
22 * and scalars totalling exactly the right number of scalar components.
23 *
24 * Matrix constructors will always consist of either exactly 1 scalar, exactly 1 matrix, or a
25 * collection of vectors and scalars totalling exactly the right number of scalar components.
ethannicholasb3058bd2016-07-01 08:22:01 -070026 */
27struct Constructor : public Expression {
Greg Daniel64773e62016-11-22 09:44:03 -050028 Constructor(Position position, const Type& type,
ethannicholasb3058bd2016-07-01 08:22:01 -070029 std::vector<std::unique_ptr<Expression>> arguments)
ethannicholasd598f792016-07-25 10:08:54 -070030 : INHERITED(position, kConstructor_Kind, type)
ethannicholasb3058bd2016-07-01 08:22:01 -070031 , fArguments(std::move(arguments)) {}
32
Ethan Nicholascb670962017-04-20 19:31:52 -040033 std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
34 const DefinitionMap& definitions) override {
35 if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind) {
Brian Salomon1d816b92017-08-17 11:07:59 -040036 if (fType == *irGenerator.fContext.fFloat_Type) {
Ethan Nicholascb670962017-04-20 19:31:52 -040037 // 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 fPosition,
41 intValue));
Brian Salomon1d816b92017-08-17 11:07:59 -040042 } else if (fType == *irGenerator.fContext.fUInt_Type) {
Ethan Nicholascb670962017-04-20 19:31:52 -040043 // promote uint(1) to 1u
44 int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue;
45 return std::unique_ptr<Expression>(new IntLiteral(irGenerator.fContext,
46 fPosition,
47 intValue,
48 &fType));
49 }
Ethan Nicholas86a43402017-01-19 13:32:00 -050050 }
51 return nullptr;
52 }
53
Ethan Nicholascb670962017-04-20 19:31:52 -040054 bool hasSideEffects() const override {
55 for (const auto& arg : fArguments) {
56 if (arg->hasSideEffects()) {
57 return true;
58 }
59 }
60 return false;
61 }
62
Ethan Nicholas0df1b042017-03-31 13:56:23 -040063 String description() const override {
64 String result = fType.description() + "(";
65 String separator;
ethannicholasb3058bd2016-07-01 08:22:01 -070066 for (size_t i = 0; i < fArguments.size(); i++) {
67 result += separator;
68 result += fArguments[i]->description();
69 separator = ", ";
70 }
71 result += ")";
72 return result;
73 }
74
75 bool isConstant() const override {
76 for (size_t i = 0; i < fArguments.size(); i++) {
77 if (!fArguments[i]->isConstant()) {
78 return false;
79 }
80 }
81 return true;
82 }
83
Ethan Nicholas3deaeb22017-04-25 14:42:11 -040084 bool compareConstant(const Context& context, const Expression& other) const override {
85 ASSERT(other.fKind == Expression::kConstructor_Kind && other.fType == fType);
86 Constructor& c = (Constructor&) other;
87 if (c.fType.kind() == Type::kVector_Kind) {
88 for (int i = 0; i < fType.columns(); i++) {
89 if (!this->getVecComponent(i).compareConstant(context, c.getVecComponent(i))) {
90 return false;
91 }
92 }
93 return true;
94 }
95 // shouldn't be possible to have a constant constructor that isn't a vector or matrix;
96 // a constant scalar constructor should have been collapsed down to the appropriate
97 // literal
98 ASSERT(fType.kind() == Type::kMatrix_Kind);
99 const FloatLiteral fzero(context, Position(), 0);
100 const IntLiteral izero(context, Position(), 0);
101 const Expression* zero;
102 if (fType.componentType() == *context.fFloat_Type) {
103 zero = &fzero;
104 } else {
105 ASSERT(fType.componentType() == *context.fInt_Type);
106 zero = &izero;
107 }
108 for (int col = 0; col < fType.columns(); col++) {
109 for (int row = 0; row < fType.rows(); row++) {
110 const Expression* component1 = getMatComponent(col, row);
111 const Expression* component2 = c.getMatComponent(col, row);
112 if (!(component1 ? component1 : zero)->compareConstant(
113 context,
114 component2 ? *component2 : *zero)) {
115 return false;
116 }
117 }
118 }
119 return true;
120 }
121
Ethan Nicholascb670962017-04-20 19:31:52 -0400122 const Expression& getVecComponent(int index) const {
123 ASSERT(fType.kind() == Type::kVector_Kind);
124 if (fArguments.size() == 1 && fArguments[0]->fType.kind() == Type::kScalar_Kind) {
125 return *fArguments[0];
126 }
127 int current = 0;
128 for (const auto& arg : fArguments) {
129 ASSERT(current <= index);
130 if (arg->fType.kind() == Type::kScalar_Kind) {
131 if (index == current) {
132 return *arg;
133 }
134 current++;
135 } else {
136 ASSERT(arg->fType.kind() == Type::kVector_Kind);
137 ASSERT(arg->fKind == Expression::kConstructor_Kind);
138 if (current + arg->fType.columns() > index) {
139 return ((const Constructor&) *arg).getVecComponent(index - current);
140 }
141 current += arg->fType.columns();
142 }
143 }
144 ABORT("failed to find vector component %d in %s\n", index, description().c_str());
145 }
146
147 double getFVecComponent(int index) const {
148 const Expression& c = this->getVecComponent(index);
149 ASSERT(c.fKind == Expression::kFloatLiteral_Kind);
150 return ((FloatLiteral&) c).fValue;
151 }
152
153 int64_t getIVecComponent(int index) const {
154 const Expression& c = this->getVecComponent(index);
155 ASSERT(c.fKind == Expression::kIntLiteral_Kind);
156 return ((IntLiteral&) c).fValue;
157 }
158
Ethan Nicholas3deaeb22017-04-25 14:42:11 -0400159 // null return should be interpreted as zero
160 const Expression* getMatComponent(int col, int row) const {
161 ASSERT(this->isConstant());
162 ASSERT(fType.kind() == Type::kMatrix_Kind);
163 ASSERT(col < fType.columns() && row < fType.rows());
164 if (fArguments.size() == 1) {
165 if (fArguments[0]->fType.kind() == Type::kScalar_Kind) {
166 // single scalar argument, so matrix is of the form:
167 // x 0 0
168 // 0 x 0
169 // 0 0 x
170 // return x if col == row
171 return col == row ? fArguments[0].get() : nullptr;
172 }
173 if (fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
174 ASSERT(fArguments[0]->fKind == Expression::kConstructor_Kind);
175 // single matrix argument. make sure we're within the argument's bounds.
176 const Type& argType = ((Constructor&) *fArguments[0]).fType;
177 if (col < argType.columns() && row < argType.rows()) {
178 // within bounds, defer to argument
179 return ((Constructor&) *fArguments[0]).getMatComponent(col, row);
180 }
181 // out of bounds, return 0
182 return nullptr;
183 }
184 }
185 int currentIndex = 0;
186 int targetIndex = col * fType.rows() + row;
187 for (const auto& arg : fArguments) {
188 ASSERT(targetIndex >= currentIndex);
189 ASSERT(arg->fType.rows() == 1);
190 if (currentIndex + arg->fType.columns() > targetIndex) {
191 if (arg->fType.columns() == 1) {
192 return arg.get();
193 } else {
194 ASSERT(arg->fType.kind() == Type::kVector_Kind);
195 ASSERT(arg->fKind == Expression::kConstructor_Kind);
196 return &((Constructor&) *arg).getVecComponent(targetIndex - currentIndex);
197 }
198 }
199 currentIndex += arg->fType.columns();
200 }
201 ABORT("can't happen, matrix component out of bounds");
202 }
203
Ethan Nicholas86a43402017-01-19 13:32:00 -0500204 std::vector<std::unique_ptr<Expression>> fArguments;
ethannicholasb3058bd2016-07-01 08:22:01 -0700205
206 typedef Expression INHERITED;
207};
208
209} // namespace
210
211#endif