blob: d6e5aad37d2ed69de177497bea58a96bfdc53b46 [file] [log] [blame]
Brian Osman0a442b72020-12-02 11:12:51 -05001/*
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/private/SkTArray.h"
9#include "src/sksl/SkSLCodeGenerator.h"
10#include "src/sksl/SkSLVMGenerator.h"
11#include "src/sksl/ir/SkSLBinaryExpression.h"
12#include "src/sksl/ir/SkSLBlock.h"
13#include "src/sksl/ir/SkSLBoolLiteral.h"
14#include "src/sksl/ir/SkSLBreakStatement.h"
15#include "src/sksl/ir/SkSLConstructor.h"
16#include "src/sksl/ir/SkSLContinueStatement.h"
17#include "src/sksl/ir/SkSLDoStatement.h"
18#include "src/sksl/ir/SkSLExpressionStatement.h"
19#include "src/sksl/ir/SkSLExternalFunctionCall.h"
20#include "src/sksl/ir/SkSLExternalValueReference.h"
21#include "src/sksl/ir/SkSLFieldAccess.h"
22#include "src/sksl/ir/SkSLFloatLiteral.h"
23#include "src/sksl/ir/SkSLForStatement.h"
24#include "src/sksl/ir/SkSLFunctionCall.h"
25#include "src/sksl/ir/SkSLFunctionDeclaration.h"
26#include "src/sksl/ir/SkSLFunctionDefinition.h"
27#include "src/sksl/ir/SkSLIfStatement.h"
28#include "src/sksl/ir/SkSLIndexExpression.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
Brian Osman0a442b72020-12-02 11:12:51 -050030#include "src/sksl/ir/SkSLPostfixExpression.h"
31#include "src/sksl/ir/SkSLPrefixExpression.h"
32#include "src/sksl/ir/SkSLProgramElement.h"
33#include "src/sksl/ir/SkSLReturnStatement.h"
34#include "src/sksl/ir/SkSLStatement.h"
35#include "src/sksl/ir/SkSLSwitchStatement.h"
36#include "src/sksl/ir/SkSLSwizzle.h"
37#include "src/sksl/ir/SkSLTernaryExpression.h"
38#include "src/sksl/ir/SkSLVarDeclarations.h"
39#include "src/sksl/ir/SkSLVariableReference.h"
40
41#include <algorithm>
42#include <unordered_map>
43
Brian Osman0a442b72020-12-02 11:12:51 -050044namespace SkSL {
45
46namespace {
47
48class DebugfErrorReporter : public ErrorReporter {
49public:
50 void error(int offset, String msg) override {
51 SkDebugf("%s\n", msg.c_str());
52 ++fErrorCount;
53 }
54 int errorCount() override { return fErrorCount; }
55
56private:
57 int fErrorCount = 0;
58};
59
60// Holds scalars, vectors, or matrices
61struct Value {
62 Value() = default;
63 explicit Value(size_t slots) {
64 fVals.resize(slots);
65 }
66 Value(skvm::F32 x) : fVals({ x.id }) {}
67 Value(skvm::I32 x) : fVals({ x.id }) {}
68
69 explicit operator bool() const { return !fVals.empty(); }
70
71 size_t slots() const { return fVals.size(); }
72
73 struct ValRef {
74 ValRef(skvm::Val& val) : fVal(val) {}
75
76 ValRef& operator=(ValRef v) { fVal = v.fVal; return *this; }
77 ValRef& operator=(skvm::Val v) { fVal = v; return *this; }
78 ValRef& operator=(skvm::F32 v) { fVal = v.id; return *this; }
79 ValRef& operator=(skvm::I32 v) { fVal = v.id; return *this; }
80
81 operator skvm::Val() { return fVal; }
82
83 skvm::Val& fVal;
84 };
85
86 ValRef operator[](int i) { return fVals[i]; }
87 skvm::Val operator[](int i) const { return fVals[i]; }
88
89private:
90 SkSTArray<4, skvm::Val, true> fVals;
91};
92
93} // namespace
94
95class SkVMGenerator {
96public:
97 SkVMGenerator(const Program& program,
98 const FunctionDefinition& function,
99 skvm::Builder* builder,
100 SkSpan<skvm::Val> uniforms,
101 SkSpan<skvm::Val> params,
102 skvm::Coord device,
103 skvm::Coord local,
104 SampleChildFn sampleChild,
105 SkSpan<skvm::Val> outReturn,
106 ErrorReporter* errors);
107
108 bool generateCode();
109
110private:
111 enum class Intrinsic {
112 // sksl_public.sksl declares these intrinsics (and defines some other inline)
113
114 // Angle & Trigonometry
115 kSin,
116 kCos,
117 kTan,
118
119 kASin,
120 kACos,
121 kATan,
122
123 // Exponential
124 kPow,
125 kExp,
126 kLog,
127 kExp2,
128 kLog2,
129
130 kSqrt,
131 kInverseSqrt,
132
133 // Common
134 kAbs,
135 kSign,
136 kFloor,
137 kCeil,
138 kFract,
139 kMod,
140
141 kMin,
142 kMax,
143 kClamp,
144 kSaturate,
145 kMix,
146 kStep,
147 kSmoothstep,
148
149 // Geometric
150 kLength,
151 kDistance,
152 kDot,
153 kNormalize,
154
155 // Matrix
Brian Osman93aed9a2020-12-28 15:18:46 -0500156 kMatrixCompMult,
Brian Osman0a442b72020-12-02 11:12:51 -0500157 kInverse,
158
159 // Vector Relational
160 kLessThan,
161 kLessThanEqual,
162 kGreaterThan,
163 kGreaterThanEqual,
164 kEqual,
165 kNotEqual,
166
167 kAny,
168 kAll,
169 kNot,
170
171 // SkSL
172 kSample,
173 };
174
175 using Slot = size_t;
176
177 /**
178 * In SkSL, a Variable represents a named, typed value (along with qualifiers, etc).
179 * Every Variable is mapped to one (or several, contiguous) Slots -- indices into our vector of
180 * skvm::Val. Those skvm::Val entries hold the current actual value of that variable.
181 *
182 * NOTE: Conceptually, each Variable is just mapped to a Value. We could implement it that way,
183 * (and eliminate the Slot indirection), but it would add overhead for each Variable,
184 * and add additional (different) bookkeeping for things like lvalue-swizzles.
185 *
186 * Any time a variable appears in an expression, that's a VariableReference, which is a kind of
187 * Expression. Evaluating that VariableReference (or any other Expression) produces a Value,
188 * which is a set of skvm::Val. (This allows an Expression to produce a vector or matrix, in
189 * addition to a scalar).
190 *
191 * For a VariableReference, producing a Value is straightforward - we get the Slot of the
192 * Variable, use that to look up the current skvm::Vals holding the variable's contents, and
193 * construct a Value with those ids.
194 */
195
196 /**
197 * Returns the Slot holding v's Val(s). Allocates storage if this is first time 'v' is
198 * referenced. Compound variables (e.g. vectors) will consume more than one slot, with
199 * getSlot returning the start of the contiguous chunk of slots.
200 */
201 Slot getSlot(const Variable& v);
202
203 /**
204 * As above, but computes the Slot of an expression involving indexing & field access.
205 * The expression doesn't have separate storage - this returns the Slot of the underlying
206 * Variable, with some offset applied to account for the indexing and field access.
207 */
208 Slot getSlot(const Expression& e);
209
210 skvm::F32 f32(skvm::Val id) { return {fBuilder, id}; }
211 skvm::I32 i32(skvm::Val id) { return {fBuilder, id}; }
212
213 // Shorthand for scalars
214 skvm::F32 f32(const Value& v) { SkASSERT(v.slots() == 1); return f32(v[0]); }
215 skvm::I32 i32(const Value& v) { SkASSERT(v.slots() == 1); return i32(v[0]); }
216
217 template <typename Fn>
218 Value unary(const Value& v, Fn&& fn) {
219 Value result(v.slots());
220 for (size_t i = 0; i < v.slots(); ++i) {
221 result[i] = fn({fBuilder, v[i]});
222 }
223 return result;
224 }
225
226 skvm::I32 mask() { return fMask; }
227
228 Value writeExpression(const Expression& expr);
229 Value writeBinaryExpression(const BinaryExpression& b);
230 Value writeConstructor(const Constructor& c);
231 Value writeFunctionCall(const FunctionCall& c);
232 Value writeIntrinsicCall(const FunctionCall& c);
233 Value writePostfixExpression(const PostfixExpression& p);
234 Value writePrefixExpression(const PrefixExpression& p);
235 Value writeSwizzle(const Swizzle& swizzle);
236 Value writeTernaryExpression(const TernaryExpression& t);
237 Value writeVariableExpression(const Expression& expr);
238
239 void writeStatement(const Statement& s);
240 void writeBlock(const Block& b);
241 void writeIfStatement(const IfStatement& stmt);
242 void writeReturnStatement(const ReturnStatement& r);
243 void writeVarDeclaration(const VarDeclaration& decl);
244
245 Value writeStore(const Expression& lhs, const Value& rhs);
246
247 Value writeMatrixInverse2x2(const Value& m);
248 Value writeMatrixInverse3x3(const Value& m);
249 Value writeMatrixInverse4x4(const Value& m);
250
251 const Program& fProgram;
252 const FunctionDefinition& fFunction;
253
254 skvm::Builder* fBuilder;
255
256 std::vector<skvm::Val> fSlots;
257 const skvm::Coord fLocalCoord;
258 const SampleChildFn fSampleChild;
259 const SkSpan<skvm::Val> fReturnValue;
260
261 ErrorReporter& fErrors;
262
263 skvm::I32 fMask;
264 skvm::I32 fReturned;
265
266 // [Variable, first slot in fSlots]
267 std::unordered_map<const Variable*, Slot> fVariableMap;
268
269 const std::unordered_map<String, Intrinsic> fIntrinsics;
270
271 class AutoMask {
272 public:
273 AutoMask(SkVMGenerator* generator, skvm::I32 mask)
274 : fGenerator(generator), fOldMask(fGenerator->fMask) {
275 fGenerator->fMask &= mask;
276 }
277
278 ~AutoMask() { fGenerator->fMask = fOldMask; }
279
280 private:
281 SkVMGenerator* fGenerator;
282 skvm::I32 fOldMask;
283 };
284};
285
286static Type::NumberKind base_number_kind(const Type& type) {
287 if (type.typeKind() == Type::TypeKind::kMatrix || type.typeKind() == Type::TypeKind::kVector) {
288 return base_number_kind(type.componentType());
289 }
290 return type.numberKind();
291}
292
293static inline bool is_uniform(const SkSL::Variable& var) {
294 return var.modifiers().fFlags & Modifiers::kUniform_Flag;
295}
296
297static size_t slot_count(const Type& type) {
298 switch (type.typeKind()) {
299 case Type::TypeKind::kOther:
300 return 0;
301 case Type::TypeKind::kStruct: {
302 size_t slots = 0;
303 for (const auto& f : type.fields()) {
304 slots += slot_count(*f.fType);
305 }
306 return slots;
307 }
308 case Type::TypeKind::kArray:
309 SkASSERT(type.columns() > 0);
310 return type.columns() * slot_count(type.componentType());
311 default:
312 return type.columns() * type.rows();
313 }
314}
315
316SkVMGenerator::SkVMGenerator(const Program& program,
317 const FunctionDefinition& function,
318 skvm::Builder* builder,
319 SkSpan<skvm::Val> uniforms,
320 SkSpan<skvm::Val> params,
321 skvm::Coord device,
322 skvm::Coord local,
323 SampleChildFn sampleChild,
324 SkSpan<skvm::Val> outReturn,
325 ErrorReporter* errors)
326 : fProgram(program)
327 , fFunction(function)
328 , fBuilder(builder)
329 , fLocalCoord(local)
330 , fSampleChild(std::move(sampleChild))
331 , fReturnValue(outReturn)
332 , fErrors(*errors)
333 , fIntrinsics {
334 { "sin", Intrinsic::kSin },
335 { "cos", Intrinsic::kCos },
336 { "tan", Intrinsic::kTan },
337 { "asin", Intrinsic::kASin },
338 { "acos", Intrinsic::kACos },
339 { "atan", Intrinsic::kATan },
340
341 { "pow", Intrinsic::kPow },
342 { "exp", Intrinsic::kExp },
343 { "log", Intrinsic::kLog },
344 { "exp2", Intrinsic::kExp2 },
345 { "log2", Intrinsic::kLog2 },
346 { "sqrt", Intrinsic::kSqrt },
347 { "inversesqrt", Intrinsic::kInverseSqrt },
348
349 { "abs", Intrinsic::kAbs },
350 { "sign", Intrinsic::kSign },
351 { "floor", Intrinsic::kFloor },
352 { "ceil", Intrinsic::kCeil },
353 { "fract", Intrinsic::kFract },
354 { "mod", Intrinsic::kMod },
355
356 { "min", Intrinsic::kMin },
357 { "max", Intrinsic::kMax },
358 { "clamp", Intrinsic::kClamp },
359 { "saturate", Intrinsic::kSaturate },
360 { "mix", Intrinsic::kMix },
361 { "step", Intrinsic::kStep },
362 { "smoothstep", Intrinsic::kSmoothstep },
363
364 { "length", Intrinsic::kLength },
365 { "distance", Intrinsic::kDistance },
366 { "dot", Intrinsic::kDot },
367 { "normalize", Intrinsic::kNormalize },
368
Brian Osman93aed9a2020-12-28 15:18:46 -0500369 { "matrixCompMult", Intrinsic::kMatrixCompMult },
370 { "inverse", Intrinsic::kInverse },
Brian Osman0a442b72020-12-02 11:12:51 -0500371
372 { "lessThan", Intrinsic::kLessThan },
373 { "lessThanEqual", Intrinsic::kLessThanEqual },
374 { "greaterThan", Intrinsic::kGreaterThan },
375 { "greaterThanEqual", Intrinsic::kGreaterThanEqual },
376 { "equal", Intrinsic::kEqual },
377 { "notEqual", Intrinsic::kNotEqual },
378
379 { "any", Intrinsic::kAny },
380 { "all", Intrinsic::kAll },
381 { "not", Intrinsic::kNot },
382
383 { "sample", Intrinsic::kSample },
384 } {
385 fMask = fBuilder->splat(0xffff'ffff);
386 fReturned = fBuilder->splat(0);
387
388 // Now, add storage for each global variable (including uniforms) to fSlots, and entries in
389 // fVariableMap to remember where every variable is stored.
390 const skvm::Val* uniformIter = uniforms.begin();
391 size_t fpCount = 0;
392 for (const ProgramElement* e : fProgram.elements()) {
393 if (e->is<GlobalVarDeclaration>()) {
394 const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
395 const Variable& var = decl.declaration()->as<VarDeclaration>().var();
396 SkASSERT(fVariableMap.find(&var) == fVariableMap.end());
397
398 // For most variables, fVariableMap stores an index into fSlots, but for fragment
399 // processors (child shaders), fVariableMap stores the index to pass to fSampleChild().
400 if (var.type() == *fProgram.fContext->fFragmentProcessor_Type) {
401 fVariableMap[&var] = fpCount++;
402 continue;
403 }
404
405 // Opaque types include fragment processors, GL objects (samplers, textures, etc), and
406 // special types like 'void'. Of those, only fragment processors are legal variables.
407 SkASSERT(!var.type().isOpaque());
408
409 size_t nslots = slot_count(var.type());
410 fVariableMap[&var] = fSlots.size();
411
412 if (int builtin = var.modifiers().fLayout.fBuiltin; builtin >= 0) {
413 // builtin variables are system-defined, with special semantics. The only builtin
414 // variable exposed to runtime effects is sk_FragCoord.
415 switch (builtin) {
416 case SK_FRAGCOORD_BUILTIN:
417 SkASSERT(nslots == 4);
418 fSlots.insert(fSlots.end(), {device.x.id,
419 device.y.id,
420 fBuilder->splat(0.0f).id,
421 fBuilder->splat(1.0f).id});
422 break;
423 default:
424 SkDEBUGFAIL("Unsupported builtin");
425 }
426 } else if (is_uniform(var)) {
427 // For uniforms, copy the supplied IDs over
428 SkASSERT(uniformIter + nslots <= uniforms.end());
429 fSlots.insert(fSlots.end(), uniformIter, uniformIter + nslots);
430 uniformIter += nslots;
431 } else {
432 // For other globals, initialize them to zero
433 fSlots.insert(fSlots.end(), nslots, fBuilder->splat(0.0f).id);
434 }
435 }
436 }
437 SkASSERT(uniformIter == uniforms.end());
438
439 const FunctionDeclaration& decl = fFunction.declaration();
440
441 // Ensure that outReturn (where we place the return values) is the correct size
442 SkASSERT(slot_count(decl.returnType()) == fReturnValue.size());
443
444 // Copy parameter IDs to our list of (all) variable IDs
445 size_t paramBase = fSlots.size(),
446 paramSlot = paramBase;
447 fSlots.insert(fSlots.end(), params.begin(), params.end());
448
449 // Compute where each parameter variable lives in the variable ID list
450 for (const Variable* p : decl.parameters()) {
451 fVariableMap[p] = paramSlot;
452 paramSlot += slot_count(p->type());
453 }
454 SkASSERT(paramSlot == fSlots.size());
455}
456
457bool SkVMGenerator::generateCode() {
458 this->writeStatement(*fFunction.body());
459 return 0 == fErrors.errorCount();
460}
461
462SkVMGenerator::Slot SkVMGenerator::getSlot(const Variable& v) {
463 auto entry = fVariableMap.find(&v);
464 if (entry != fVariableMap.end()) {
465 return entry->second;
466 }
467
468 SkASSERT(!is_uniform(v)); // Should have been added at construction time
469
470 size_t slot = fSlots.size(),
471 nslots = slot_count(v.type());
472 fSlots.resize(slot + nslots, fBuilder->splat(0.0f).id);
473 fVariableMap[&v] = slot;
474 return slot;
475}
476
477SkVMGenerator::Slot SkVMGenerator::getSlot(const Expression& e) {
478 switch (e.kind()) {
479 case Expression::Kind::kFieldAccess: {
480 const FieldAccess& f = e.as<FieldAccess>();
481 Slot slot = this->getSlot(*f.base());
482 for (int i = 0; i < f.fieldIndex(); ++i) {
483 slot += slot_count(*f.base()->type().fields()[i].fType);
484 }
485 return slot;
486 }
487 case Expression::Kind::kIndex: {
488 const IndexExpression& i = e.as<IndexExpression>();
489 Slot baseSlot = this->getSlot(*i.base());
490
491 const Expression& index = *i.index();
492 SkASSERT(index.isCompileTimeConstant());
493
John Stiles12739df2020-12-29 09:47:20 -0500494 SKSL_INT indexValue = index.getConstantInt();
Brian Osman0a442b72020-12-02 11:12:51 -0500495 SkASSERT(indexValue >= 0 && indexValue < i.base()->type().columns());
496
497 size_t stride = slot_count(i.type());
498 return baseSlot + indexValue * stride;
499 }
500 case Expression::Kind::kVariableReference:
501 return this->getSlot(*e.as<VariableReference>().variable());
502 default:
503 SkDEBUGFAIL("Invalid expression type");
504 return ~static_cast<Slot>(0);
505 }
506}
507
508Value SkVMGenerator::writeBinaryExpression(const BinaryExpression& b) {
509 const Expression& left = *b.left();
510 const Expression& right = *b.right();
511 Token::Kind op = b.getOperator();
512 if (op == Token::Kind::TK_EQ) {
513 return this->writeStore(left, this->writeExpression(right));
514 }
515
516 const Type& lType = left.type();
517 const Type& rType = right.type();
518 bool lVecOrMtx = (lType.isVector() || lType.isMatrix());
519 bool rVecOrMtx = (rType.isVector() || rType.isMatrix());
520 bool isAssignment = Compiler::IsAssignment(op);
521 if (isAssignment) {
522 op = Compiler::RemoveAssignment(op);
523 }
524 Type::NumberKind nk = base_number_kind(lType);
525
526 // A few ops require special treatment:
527 switch (op) {
528 case Token::Kind::TK_LOGICALAND: {
529 SkASSERT(!isAssignment);
530 SkASSERT(nk == Type::NumberKind::kBoolean);
531 skvm::I32 lVal = i32(this->writeExpression(left));
532 AutoMask shortCircuit(this, lVal);
533 skvm::I32 rVal = i32(this->writeExpression(right));
534 return lVal & rVal;
535 }
536 case Token::Kind::TK_LOGICALOR: {
537 SkASSERT(!isAssignment);
538 SkASSERT(nk == Type::NumberKind::kBoolean);
539 skvm::I32 lVal = i32(this->writeExpression(left));
540 AutoMask shortCircuit(this, ~lVal);
541 skvm::I32 rVal = i32(this->writeExpression(right));
542 return lVal | rVal;
543 }
544 default:
545 break;
546 }
547
548 // All of the other ops always evaluate both sides of the expression
549 Value lVal = this->writeExpression(left),
550 rVal = this->writeExpression(right);
551
552 // Special case for M*V, V*M, M*M (but not V*V!)
553 if (op == Token::Kind::TK_STAR
554 && lVecOrMtx && rVecOrMtx && !(lType.isVector() && rType.isVector())) {
555 int rCols = rType.columns(),
556 rRows = rType.rows(),
557 lCols = lType.columns(),
558 lRows = lType.rows();
559 // M*V treats the vector as a column
560 if (rType.isVector()) {
561 std::swap(rCols, rRows);
562 }
563 SkASSERT(lCols == rRows);
564 SkASSERT(slot_count(b.type()) == static_cast<size_t>(lRows * rCols));
565 Value result(lRows * rCols);
566 size_t resultIdx = 0;
567 for (int c = 0; c < rCols; ++c)
568 for (int r = 0; r < lRows; ++r) {
569 skvm::F32 sum = fBuilder->splat(0.0f);
570 for (int j = 0; j < lCols; ++j) {
571 sum += f32(lVal[j*lRows + r]) * f32(rVal[c*rRows + j]);
572 }
573 result[resultIdx++] = sum;
574 }
575 SkASSERT(resultIdx == result.slots());
576 return isAssignment ? this->writeStore(left, result) : result;
577 }
578
579 size_t nslots = std::max(lVal.slots(), rVal.slots());
580
581 // TODO: This treats all unsigned types as signed. Need to pick a policy. (Either produce errors
582 // if a program uses unsigned types, or just silently convert everything to signed?)
583 auto binary = [&](auto&& f_fn, auto&& i_fn) {
584 Value result(nslots);
585 for (size_t i = 0; i < nslots; ++i) {
586 // If one side is scalar, replicate it to all channels
587 skvm::Val L = lVal.slots() == 1 ? lVal[0] : lVal[i],
588 R = rVal.slots() == 1 ? rVal[0] : rVal[i];
589 if (nk == Type::NumberKind::kFloat) {
590 result[i] = f_fn(f32(L), f32(R));
591 } else {
592 result[i] = i_fn(i32(L), i32(R));
593 }
594 }
595 return isAssignment ? this->writeStore(left, result) : result;
596 };
597
598 auto unsupported_f = [&](skvm::F32, skvm::F32) {
599 SkDEBUGFAIL("Unsupported operator");
600 return skvm::F32{};
601 };
602
603 switch (op) {
604 case Token::Kind::TK_EQEQ: {
605 SkASSERT(!isAssignment);
606 Value cmp = binary([](skvm::F32 x, skvm::F32 y) { return x == y; },
607 [](skvm::I32 x, skvm::I32 y) { return x == y; });
608 skvm::I32 folded = i32(cmp[0]);
609 for (size_t i = 1; i < nslots; ++i) {
610 folded &= i32(cmp[i]);
611 }
612 return folded;
613 }
614 case Token::Kind::TK_NEQ: {
615 SkASSERT(!isAssignment);
616 Value cmp = binary([](skvm::F32 x, skvm::F32 y) { return x != y; },
617 [](skvm::I32 x, skvm::I32 y) { return x != y; });
618 skvm::I32 folded = i32(cmp[0]);
619 for (size_t i = 1; i < nslots; ++i) {
620 folded |= i32(cmp[i]);
621 }
622 return folded;
623 }
624 case Token::Kind::TK_GT:
625 return binary([](skvm::F32 x, skvm::F32 y) { return x > y; },
626 [](skvm::I32 x, skvm::I32 y) { return x > y; });
627 case Token::Kind::TK_GTEQ:
628 return binary([](skvm::F32 x, skvm::F32 y) { return x >= y; },
629 [](skvm::I32 x, skvm::I32 y) { return x >= y; });
630 case Token::Kind::TK_LT:
631 return binary([](skvm::F32 x, skvm::F32 y) { return x < y; },
632 [](skvm::I32 x, skvm::I32 y) { return x < y; });
633 case Token::Kind::TK_LTEQ:
634 return binary([](skvm::F32 x, skvm::F32 y) { return x <= y; },
635 [](skvm::I32 x, skvm::I32 y) { return x <= y; });
636
637 case Token::Kind::TK_PLUS:
638 return binary([](skvm::F32 x, skvm::F32 y) { return x + y; },
639 [](skvm::I32 x, skvm::I32 y) { return x + y; });
640 case Token::Kind::TK_MINUS:
641 return binary([](skvm::F32 x, skvm::F32 y) { return x - y; },
642 [](skvm::I32 x, skvm::I32 y) { return x - y; });
643 case Token::Kind::TK_STAR:
644 return binary([](skvm::F32 x, skvm::F32 y) { return x * y; },
645 [](skvm::I32 x, skvm::I32 y) { return x * y; });
646 case Token::Kind::TK_SLASH:
647 // Minimum spec (GLSL ES 1.0) has very loose requirements for integer operations.
648 // (Low-end GPUs may not have integer ALUs). Given that, we are allowed to do floating
649 // point division plus rounding. Section 10.28 of the spec even clarifies that the
650 // rounding mode is undefined (but round-towards-zero is the obvious/common choice).
651 return binary([](skvm::F32 x, skvm::F32 y) { return x / y; },
652 [](skvm::I32 x, skvm::I32 y) {
653 return skvm::trunc(skvm::to_F32(x) / skvm::to_F32(y));
654 });
655
656 case Token::Kind::TK_BITWISEXOR:
657 case Token::Kind::TK_LOGICALXOR:
658 return binary(unsupported_f, [](skvm::I32 x, skvm::I32 y) { return x ^ y; });
659 case Token::Kind::TK_BITWISEAND:
660 return binary(unsupported_f, [](skvm::I32 x, skvm::I32 y) { return x & y; });
661 case Token::Kind::TK_BITWISEOR:
662 return binary(unsupported_f, [](skvm::I32 x, skvm::I32 y) { return x | y; });
663
664 // These three operators are all 'reserved' (illegal) in our minimum spec, but will require
665 // implementation in the future.
666 case Token::Kind::TK_PERCENT:
667 case Token::Kind::TK_SHL:
668 case Token::Kind::TK_SHR:
669 default:
670 SkDEBUGFAIL("Unsupported operator");
671 return {};
672 }
673}
674
675Value SkVMGenerator::writeConstructor(const Constructor& c) {
676 if (c.arguments().size() > 1) {
677 // Multi-argument constructors just aggregate their arguments, with no conversion
678 // NOTE: This (SkSL rule) is actually more restrictive than GLSL.
679 Value result(slot_count(c.type()));
680 size_t resultIdx = 0;
681 for (const auto &arg : c.arguments()) {
682 Value tmp = this->writeExpression(*arg);
683 for (size_t tmpSlot = 0; tmpSlot < tmp.slots(); ++tmpSlot) {
684 result[resultIdx++] = tmp[tmpSlot];
685 }
686 }
687 return result;
688 }
689
690 const Type& srcType = c.arguments()[0]->type();
691 const Type& dstType = c.type();
692 Type::NumberKind srcKind = base_number_kind(srcType),
693 dstKind = base_number_kind(dstType);
694 Value src = this->writeExpression(*c.arguments()[0]);
695 size_t dstSlots = slot_count(dstType);
696
697 // Conversion among "similar" types (floatN <-> halfN), (shortN <-> intN), etc. is a no-op
698 if (srcKind == dstKind && src.slots() == dstSlots) {
699 return src;
700 }
701
702 // TODO: Handle conversion to/from bool
703 // TODO: Handle signed vs. unsigned? GLSL ES 1.0 only has 'int', so no problem yet
704 if (srcKind != dstKind) {
705 // One argument constructors can do type conversion
706 Value dst(src.slots());
707 if (dstKind == Type::NumberKind::kFloat) {
708 SkASSERT(srcKind == Type::NumberKind::kSigned);
709 for (size_t i = 0; i < src.slots(); ++i) {
710 dst[i] = skvm::to_F32(i32(src[i]));
711 }
712 } else if (dstKind == Type::NumberKind::kSigned) {
713 SkASSERT(srcKind == Type::NumberKind::kFloat);
714 for (size_t i = 0; i < src.slots(); ++i) {
715 dst[i] = skvm::trunc(f32(src[i]));
716 }
717 } else {
718 SkDEBUGFAIL("Unsupported type conversion");
719 }
720 return dst;
721 }
722
723 // Matrices can be constructed from scalars or other matrices
724 if (dstType.isMatrix()) {
725 Value dst(dstType.rows() * dstType.columns());
726 size_t dstIndex = 0;
727 if (srcType.isMatrix()) {
728 // Matrix-from-matrix uses src where it overlaps, fills in missing with identity
729 for (int c = 0; c < dstType.columns(); ++c)
730 for (int r = 0; r < dstType.rows(); ++r) {
731 if (c < srcType.columns() && r < srcType.rows()) {
732 dst[dstIndex++] = src[c * srcType.rows() + r];
733 } else {
734 dst[dstIndex++] = fBuilder->splat(c == r ? 1.0f : 0.0f);
735 }
736 }
737 } else if (srcType.isScalar()) {
738 // Matrix-from-scalar builds a diagonal scale matrix
739 for (int c = 0; c < dstType.columns(); ++c)
740 for (int r = 0; r < dstType.rows(); ++r) {
741 dst[dstIndex++] = (c == r ? f32(src) : fBuilder->splat(0.0f));
742 }
743 } else {
744 SkDEBUGFAIL("Invalid matrix constructor");
745 }
746 SkASSERT(dstIndex == dst.slots());
747 return dst;
748 }
749
750 // We can splat scalars to all components of a vector
751 if (dstType.isVector() && srcType.isScalar()) {
752 Value dst(dstType.columns());
753 for (int i = 0; i < dstType.columns(); ++i) {
754 dst[i] = src[0];
755 }
756 return dst;
757 }
758
759 SkDEBUGFAIL("Invalid constructor");
760 return {};
761}
762
763Value SkVMGenerator::writeVariableExpression(const Expression& e) {
764 Slot slot = this->getSlot(e);
765 Value val(slot_count(e.type()));
766 for (size_t i = 0; i < val.slots(); ++i) {
767 val[i] = fSlots[slot + i];
768 }
769 return val;
770}
771
772Value SkVMGenerator::writeMatrixInverse2x2(const Value& m) {
773 SkASSERT(m.slots() == 4);
774 skvm::F32 a = f32(m[0]),
775 b = f32(m[1]),
776 c = f32(m[2]),
777 d = f32(m[3]);
778 skvm::F32 idet = 1.0f / (a*d - b*c);
779
780 Value result(m.slots());
781 result[0] = ( d * idet);
782 result[1] = (-b * idet);
783 result[2] = (-c * idet);
784 result[3] = ( a * idet);
785 return result;
786}
787
788Value SkVMGenerator::writeMatrixInverse3x3(const Value& m) {
789 SkASSERT(m.slots() == 9);
790 skvm::F32 a11 = f32(m[0]), a12 = f32(m[3]), a13 = f32(m[6]),
791 a21 = f32(m[1]), a22 = f32(m[4]), a23 = f32(m[7]),
792 a31 = f32(m[2]), a32 = f32(m[5]), a33 = f32(m[8]);
793 skvm::F32 idet = 1.0f / (a11*a22*a33 + a12*a23*a31 + a13*a21*a32 -
794 a11*a23*a32 - a12*a21*a33 - a13*a22*a31);
795
796 Value result(m.slots());
797 result[0] = ((a22*a33 - a23*a32) * idet);
798 result[1] = ((a23*a31 - a21*a33) * idet);
799 result[2] = ((a21*a32 - a22*a31) * idet);
800 result[3] = ((a13*a32 - a12*a33) * idet);
801 result[4] = ((a11*a33 - a13*a31) * idet);
802 result[5] = ((a12*a31 - a11*a32) * idet);
803 result[6] = ((a12*a23 - a13*a22) * idet);
804 result[7] = ((a13*a21 - a11*a23) * idet);
805 result[8] = ((a11*a22 - a12*a21) * idet);
806 return result;
807}
808
809Value SkVMGenerator::writeMatrixInverse4x4(const Value& m) {
810 SkASSERT(m.slots() == 16);
811 skvm::F32 a00 = f32(m[0]), a10 = f32(m[4]), a20 = f32(m[ 8]), a30 = f32(m[12]),
812 a01 = f32(m[1]), a11 = f32(m[5]), a21 = f32(m[ 9]), a31 = f32(m[13]),
813 a02 = f32(m[2]), a12 = f32(m[6]), a22 = f32(m[10]), a32 = f32(m[14]),
814 a03 = f32(m[3]), a13 = f32(m[7]), a23 = f32(m[11]), a33 = f32(m[15]);
815
816 skvm::F32 b00 = a00*a11 - a01*a10,
817 b01 = a00*a12 - a02*a10,
818 b02 = a00*a13 - a03*a10,
819 b03 = a01*a12 - a02*a11,
820 b04 = a01*a13 - a03*a11,
821 b05 = a02*a13 - a03*a12,
822 b06 = a20*a31 - a21*a30,
823 b07 = a20*a32 - a22*a30,
824 b08 = a20*a33 - a23*a30,
825 b09 = a21*a32 - a22*a31,
826 b10 = a21*a33 - a23*a31,
827 b11 = a22*a33 - a23*a32;
828
829 skvm::F32 idet = 1.0f / (b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
830
831 b00 *= idet;
832 b01 *= idet;
833 b02 *= idet;
834 b03 *= idet;
835 b04 *= idet;
836 b05 *= idet;
837 b06 *= idet;
838 b07 *= idet;
839 b08 *= idet;
840 b09 *= idet;
841 b10 *= idet;
842 b11 *= idet;
843
844 Value result(m.slots());
845 result[ 0] = (a11*b11 - a12*b10 + a13*b09);
846 result[ 1] = (a02*b10 - a01*b11 - a03*b09);
847 result[ 2] = (a31*b05 - a32*b04 + a33*b03);
848 result[ 3] = (a22*b04 - a21*b05 - a23*b03);
849 result[ 4] = (a12*b08 - a10*b11 - a13*b07);
850 result[ 5] = (a00*b11 - a02*b08 + a03*b07);
851 result[ 6] = (a32*b02 - a30*b05 - a33*b01);
852 result[ 7] = (a20*b05 - a22*b02 + a23*b01);
853 result[ 8] = (a10*b10 - a11*b08 + a13*b06);
854 result[ 9] = (a01*b08 - a00*b10 - a03*b06);
855 result[10] = (a30*b04 - a31*b02 + a33*b00);
856 result[11] = (a21*b02 - a20*b04 - a23*b00);
857 result[12] = (a11*b07 - a10*b09 - a12*b06);
858 result[13] = (a00*b09 - a01*b07 + a02*b06);
859 result[14] = (a31*b01 - a30*b03 - a32*b00);
860 result[15] = (a20*b03 - a21*b01 + a22*b00);
861 return result;
862}
863
864Value SkVMGenerator::writeIntrinsicCall(const FunctionCall& c) {
865 auto found = fIntrinsics.find(c.function().name());
866 if (found == fIntrinsics.end()) {
Brian Osman47726a12020-12-17 16:02:08 -0500867 SkDEBUGFAILF("Missing intrinsic: '%s'", String(c.function().name()).c_str());
Brian Osman0a442b72020-12-02 11:12:51 -0500868 return {};
869 }
870
871 const size_t nargs = c.arguments().size();
872
873 if (found->second == Intrinsic::kSample) {
874 // Sample is very special, the first argument is an FP, which can't be evaluated
875 const Context& ctx = *fProgram.fContext;
876 if (nargs > 2 || c.arguments()[0]->type() != *ctx.fFragmentProcessor_Type ||
877 (nargs == 2 && (c.arguments()[1]->type() != *ctx.fFloat2_Type &&
878 c.arguments()[1]->type() != *ctx.fFloat3x3_Type))) {
879 SkDEBUGFAIL("Invalid call to sample");
880 return {};
881 }
882
883 auto fp_it = fVariableMap.find(c.arguments()[0]->as<VariableReference>().variable());
884 SkASSERT(fp_it != fVariableMap.end());
885
886 skvm::Coord coord = fLocalCoord;
887 if (nargs == 2) {
888 Value arg = this->writeExpression(*c.arguments()[1]);
889 if (arg.slots() == 2) {
890 // explicit sampling
891 coord = {f32(arg[0]), f32(arg[1])};
892 } else {
893 // matrix sampling
894 SkASSERT(arg.slots() == 9);
895 skvm::F32 x = f32(arg[0])*coord.x + f32(arg[3])*coord.y + f32(arg[6]),
896 y = f32(arg[1])*coord.x + f32(arg[4])*coord.y + f32(arg[7]),
897 w = f32(arg[2])*coord.x + f32(arg[5])*coord.y + f32(arg[8]);
898 x = x * (1.0f / w);
899 y = y * (1.0f / w);
900 coord = {x, y};
901 }
902 }
903
904 skvm::Color color = fSampleChild(fp_it->second, coord);
905 Value result(4);
906 result[0] = color.r;
907 result[1] = color.g;
908 result[2] = color.b;
909 result[3] = color.a;
910 return result;
911 }
912
913 const size_t kMaxArgs = 3; // eg: clamp, mix, smoothstep
914 Value args[kMaxArgs];
915 SkASSERT(nargs >= 1 && nargs <= SK_ARRAY_COUNT(args));
916
917 // All other intrinsics have at most three args, and those can all be evaluated up front:
918 for (size_t i = 0; i < nargs; ++i) {
919 args[i] = this->writeExpression(*c.arguments()[i]);
920 }
921 Type::NumberKind nk = base_number_kind(c.arguments()[0]->type());
922
923 auto binary = [&](auto&& fn) {
924 // Binary intrinsics are (vecN, vecN), (vecN, float), or (float, vecN)
925 size_t nslots = std::max(args[0].slots(), args[1].slots());
926 Value result(nslots);
927 SkASSERT(args[0].slots() == nslots || args[0].slots() == 1);
928 SkASSERT(args[1].slots() == nslots || args[1].slots() == 1);
929
930 for (size_t i = 0; i < nslots; ++i) {
931 result[i] = fn({fBuilder, args[0][args[0].slots() == 1 ? 0 : i]},
932 {fBuilder, args[1][args[1].slots() == 1 ? 0 : i]});
933 }
934 return result;
935 };
936
937 auto ternary = [&](auto&& fn) {
938 // Ternary intrinsics are some combination of vecN and float
939 size_t nslots = std::max({args[0].slots(), args[1].slots(), args[2].slots()});
940 Value result(nslots);
941 SkASSERT(args[0].slots() == nslots || args[0].slots() == 1);
942 SkASSERT(args[1].slots() == nslots || args[1].slots() == 1);
943 SkASSERT(args[2].slots() == nslots || args[2].slots() == 1);
944
945 for (size_t i = 0; i < nslots; ++i) {
946 result[i] = fn({fBuilder, args[0][args[0].slots() == 1 ? 0 : i]},
947 {fBuilder, args[1][args[1].slots() == 1 ? 0 : i]},
948 {fBuilder, args[2][args[2].slots() == 1 ? 0 : i]});
949 }
950 return result;
951 };
952
953 auto dot = [&](const Value& x, const Value& y) {
954 SkASSERT(x.slots() == y.slots());
955 skvm::F32 result = f32(x[0]) * f32(y[0]);
956 for (size_t i = 1; i < x.slots(); ++i) {
957 result += f32(x[i]) * f32(y[i]);
958 }
959 return result;
960 };
961
962 switch (found->second) {
963 case Intrinsic::kSin: return unary(args[0], skvm::approx_sin);
964 case Intrinsic::kCos: return unary(args[0], skvm::approx_cos);
965 case Intrinsic::kTan: return unary(args[0], skvm::approx_tan);
966
967 case Intrinsic::kASin: return unary(args[0], skvm::approx_asin);
968 case Intrinsic::kACos: return unary(args[0], skvm::approx_acos);
969
970 case Intrinsic::kATan: return nargs == 1 ? unary(args[0], skvm::approx_atan)
971 : binary(skvm::approx_atan2);
972
973 case Intrinsic::kPow:
974 return binary([](skvm::F32 x, skvm::F32 y) { return skvm::approx_powf(x, y); });
975 case Intrinsic::kExp: return unary(args[0], skvm::approx_exp);
976 case Intrinsic::kLog: return unary(args[0], skvm::approx_log);
977 case Intrinsic::kExp2: return unary(args[0], skvm::approx_pow2);
978 case Intrinsic::kLog2: return unary(args[0], skvm::approx_log2);
979
980 case Intrinsic::kSqrt: return unary(args[0], skvm::sqrt);
981 case Intrinsic::kInverseSqrt:
982 return unary(args[0], [](skvm::F32 x) { return 1.0f / skvm::sqrt(x); });
983
984 case Intrinsic::kAbs: return unary(args[0], skvm::abs);
985 case Intrinsic::kSign:
986 return unary(args[0], [](skvm::F32 x) { return select(x < 0, -1.0f,
987 select(x > 0, +1.0f, 0.0f)); });
988 case Intrinsic::kFloor: return unary(args[0], skvm::floor);
989 case Intrinsic::kCeil: return unary(args[0], skvm::ceil);
990 case Intrinsic::kFract: return unary(args[0], skvm::fract);
991 case Intrinsic::kMod:
992 return binary([](skvm::F32 x, skvm::F32 y) { return x - y*skvm::floor(x / y); });
993
994 case Intrinsic::kMin:
995 return binary([](skvm::F32 x, skvm::F32 y) { return skvm::min(x, y); });
996 case Intrinsic::kMax:
997 return binary([](skvm::F32 x, skvm::F32 y) { return skvm::max(x, y); });
998 case Intrinsic::kClamp:
999 return ternary(
1000 [](skvm::F32 x, skvm::F32 lo, skvm::F32 hi) { return skvm::clamp(x, lo, hi); });
1001 case Intrinsic::kSaturate:
1002 return unary(args[0], [](skvm::F32 x) { return skvm::clamp01(x); });
1003 case Intrinsic::kMix:
1004 return ternary(
1005 [](skvm::F32 x, skvm::F32 y, skvm::F32 t) { return skvm::lerp(x, y, t); });
1006 case Intrinsic::kStep:
1007 return binary([](skvm::F32 edge, skvm::F32 x) { return select(x < edge, 0.0f, 1.0f); });
1008 case Intrinsic::kSmoothstep:
1009 return ternary([](skvm::F32 edge0, skvm::F32 edge1, skvm::F32 x) {
1010 skvm::F32 t = skvm::clamp01((x - edge0) / (edge1 - edge0));
1011 return t * t * (3 - 2 * t);
1012 });
1013
1014 case Intrinsic::kLength: return skvm::sqrt(dot(args[0], args[0]));
1015 case Intrinsic::kDistance: {
1016 Value vec = binary([](skvm::F32 x, skvm::F32 y) { return x - y; });
1017 return skvm::sqrt(dot(vec, vec));
1018 }
1019 case Intrinsic::kDot: return dot(args[0], args[1]);
1020 case Intrinsic::kNormalize: {
1021 skvm::F32 invLen = 1.0f / skvm::sqrt(dot(args[0], args[0]));
1022 return unary(args[0], [&](skvm::F32 x) { return x * invLen; });
1023 }
1024
Brian Osman93aed9a2020-12-28 15:18:46 -05001025 case Intrinsic::kMatrixCompMult:
1026 return binary([](skvm::F32 x, skvm::F32 y) { return x * y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001027 case Intrinsic::kInverse: {
1028 switch (args[0].slots()) {
1029 case 4: return this->writeMatrixInverse2x2(args[0]);
1030 case 9: return this->writeMatrixInverse3x3(args[0]);
1031 case 16: return this->writeMatrixInverse4x4(args[0]);
1032 default:
1033 SkDEBUGFAIL("Invalid call to inverse");
1034 return {};
1035 }
1036 }
1037
1038 case Intrinsic::kLessThan:
Brian Osman30b67292020-12-23 13:02:09 -05001039 return nk == Type::NumberKind::kFloat
1040 ? binary([](skvm::F32 x, skvm::F32 y) { return x < y; })
1041 : binary([](skvm::I32 x, skvm::I32 y) { return x < y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001042 case Intrinsic::kLessThanEqual:
Brian Osman30b67292020-12-23 13:02:09 -05001043 return nk == Type::NumberKind::kFloat
1044 ? binary([](skvm::F32 x, skvm::F32 y) { return x <= y; })
1045 : binary([](skvm::I32 x, skvm::I32 y) { return x <= y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001046 case Intrinsic::kGreaterThan:
Brian Osman30b67292020-12-23 13:02:09 -05001047 return nk == Type::NumberKind::kFloat
1048 ? binary([](skvm::F32 x, skvm::F32 y) { return x > y; })
1049 : binary([](skvm::I32 x, skvm::I32 y) { return x > y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001050 case Intrinsic::kGreaterThanEqual:
Brian Osman30b67292020-12-23 13:02:09 -05001051 return nk == Type::NumberKind::kFloat
1052 ? binary([](skvm::F32 x, skvm::F32 y) { return x >= y; })
1053 : binary([](skvm::I32 x, skvm::I32 y) { return x >= y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001054
1055 case Intrinsic::kEqual:
1056 return nk == Type::NumberKind::kFloat
1057 ? binary([](skvm::F32 x, skvm::F32 y) { return x == y; })
1058 : binary([](skvm::I32 x, skvm::I32 y) { return x == y; });
1059 case Intrinsic::kNotEqual:
1060 return nk == Type::NumberKind::kFloat
1061 ? binary([](skvm::F32 x, skvm::F32 y) { return x != y; })
1062 : binary([](skvm::I32 x, skvm::I32 y) { return x != y; });
1063
1064 case Intrinsic::kAny: {
1065 skvm::I32 result = i32(args[0][0]);
1066 for (size_t i = 1; i < args[0].slots(); ++i) {
1067 result |= i32(args[0][i]);
1068 }
1069 return result;
1070 }
1071 case Intrinsic::kAll: {
1072 skvm::I32 result = i32(args[0][0]);
1073 for (size_t i = 1; i < args[0].slots(); ++i) {
1074 result &= i32(args[0][i]);
1075 }
1076 return result;
1077 }
1078 case Intrinsic::kNot: return unary(args[0], [](skvm::I32 x) { return ~x; });
1079
1080 case Intrinsic::kSample:
1081 // Handled earlier
1082 SkASSERT(false);
1083 return {};
1084 }
1085 SkUNREACHABLE;
1086}
1087
1088Value SkVMGenerator::writeFunctionCall(const FunctionCall& f) {
1089 // TODO: Support calling other functions (by recursively generating their programs, eg inlining)
1090 if (f.function().isBuiltin()) {
1091 return this->writeIntrinsicCall(f);
1092 }
1093
1094 fErrors.error(-1, "Function calls not supported yet");
1095 return {};
1096}
1097
1098Value SkVMGenerator::writePrefixExpression(const PrefixExpression& p) {
1099 Value val = this->writeExpression(*p.operand());
1100
1101 switch (p.getOperator()) {
1102 case Token::Kind::TK_PLUSPLUS:
1103 case Token::Kind::TK_MINUSMINUS: {
1104 bool incr = p.getOperator() == Token::Kind::TK_PLUSPLUS;
1105
1106 switch (base_number_kind(p.type())) {
1107 case Type::NumberKind::kFloat:
1108 val = f32(val) + fBuilder->splat(incr ? 1.0f : -1.0f);
1109 break;
1110 case Type::NumberKind::kSigned:
1111 val = i32(val) + fBuilder->splat(incr ? 1 : -1);
1112 break;
1113 default:
1114 SkASSERT(false);
1115 return {};
1116 }
1117 return this->writeStore(*p.operand(), val);
1118 }
1119 case Token::Kind::TK_MINUS: {
1120 switch (base_number_kind(p.type())) {
1121 case Type::NumberKind::kFloat:
1122 return this->unary(val, [](skvm::F32 x) { return -x; });
1123 case Type::NumberKind::kSigned:
1124 return this->unary(val, [](skvm::I32 x) { return -x; });
1125 default:
1126 SkASSERT(false);
1127 return {};
1128 }
1129 }
1130 case Token::Kind::TK_LOGICALNOT:
1131 case Token::Kind::TK_BITWISENOT:
1132 return this->unary(val, [](skvm::I32 x) { return ~x; });
1133 default:
1134 SkASSERT(false);
1135 return {};
1136 }
1137}
1138
1139Value SkVMGenerator::writePostfixExpression(const PostfixExpression& p) {
1140 switch (p.getOperator()) {
1141 case Token::Kind::TK_PLUSPLUS:
1142 case Token::Kind::TK_MINUSMINUS: {
1143 Value old = this->writeExpression(*p.operand()),
1144 val = old;
1145 SkASSERT(val.slots() == 1);
1146 bool incr = p.getOperator() == Token::Kind::TK_PLUSPLUS;
1147
1148 switch (base_number_kind(p.type())) {
1149 case Type::NumberKind::kFloat:
1150 val = f32(val) + fBuilder->splat(incr ? 1.0f : -1.0f);
1151 break;
1152 case Type::NumberKind::kSigned:
1153 val = i32(val) + fBuilder->splat(incr ? 1 : -1);
1154 break;
1155 default:
1156 SkASSERT(false);
1157 return {};
1158 }
1159 this->writeStore(*p.operand(), val);
1160 return old;
1161 }
1162 default:
1163 SkASSERT(false);
1164 return {};
1165 }
1166}
1167
1168Value SkVMGenerator::writeSwizzle(const Swizzle& s) {
1169 Value base = this->writeExpression(*s.base());
1170 Value swizzled(s.components().size());
1171 for (size_t i = 0; i < s.components().size(); ++i) {
1172 swizzled[i] = base[s.components()[i]];
1173 }
1174 return swizzled;
1175}
1176
1177Value SkVMGenerator::writeTernaryExpression(const TernaryExpression& t) {
1178 skvm::I32 test = i32(this->writeExpression(*t.test()));
1179 Value ifTrue, ifFalse;
1180
1181 {
1182 AutoMask m(this, test);
1183 ifTrue = this->writeExpression(*t.ifTrue());
1184 }
1185 {
1186 AutoMask m(this, ~test);
1187 ifFalse = this->writeExpression(*t.ifFalse());
1188 }
1189
1190 size_t nslots = ifTrue.slots();
1191 SkASSERT(nslots == ifFalse.slots());
1192
1193 Value result(nslots);
1194 for (size_t i = 0; i < nslots; ++i) {
1195 result[i] = skvm::select(test, i32(ifTrue[i]), i32(ifFalse[i]));
1196 }
1197 return result;
1198}
1199
1200Value SkVMGenerator::writeExpression(const Expression& e) {
1201 switch (e.kind()) {
1202 case Expression::Kind::kBinary:
1203 return this->writeBinaryExpression(e.as<BinaryExpression>());
1204 case Expression::Kind::kBoolLiteral:
1205 return fBuilder->splat(e.as<BoolLiteral>().value() ? ~0 : 0);
1206 case Expression::Kind::kConstructor:
1207 return this->writeConstructor(e.as<Constructor>());
1208 case Expression::Kind::kFieldAccess:
1209 case Expression::Kind::kIndex:
1210 case Expression::Kind::kVariableReference:
1211 return this->writeVariableExpression(e);
1212 case Expression::Kind::kFloatLiteral:
1213 return fBuilder->splat(e.as<FloatLiteral>().value());
1214 case Expression::Kind::kFunctionCall:
1215 return this->writeFunctionCall(e.as<FunctionCall>());
1216 case Expression::Kind::kIntLiteral:
1217 return fBuilder->splat(static_cast<int>(e.as<IntLiteral>().value()));
Brian Osman0a442b72020-12-02 11:12:51 -05001218 case Expression::Kind::kPrefix:
1219 return this->writePrefixExpression(e.as<PrefixExpression>());
1220 case Expression::Kind::kPostfix:
1221 return this->writePostfixExpression(e.as<PostfixExpression>());
1222 case Expression::Kind::kSwizzle:
1223 return this->writeSwizzle(e.as<Swizzle>());
1224 case Expression::Kind::kTernary:
1225 return this->writeTernaryExpression(e.as<TernaryExpression>());
1226 case Expression::Kind::kExternalFunctionCall:
1227 case Expression::Kind::kExternalValue:
1228 default:
1229 SkDEBUGFAIL("Unsupported expression");
1230 return {};
1231 }
1232}
1233
1234Value SkVMGenerator::writeStore(const Expression& lhs, const Value& rhs) {
1235 SkASSERT(lhs.is<FieldAccess>() || lhs.is<IndexExpression>() || lhs.is<Swizzle>() ||
1236 lhs.is<VariableReference>());
1237 SkASSERT(rhs.slots() == slot_count(lhs.type()));
1238
1239 skvm::I32 mask = this->mask();
1240 for (size_t i = rhs.slots(); i --> 0;) {
1241 const Expression* expr = &lhs;
1242 int component = i;
1243 while (expr->is<Swizzle>()) {
1244 component = expr->as<Swizzle>().components()[component];
1245 expr = expr->as<Swizzle>().base().get();
1246 }
1247 Slot slot = this->getSlot(*expr);
1248 skvm::F32 curr = f32(fSlots[slot + component]),
1249 next = f32(rhs[i]);
1250 fSlots[slot + component] = select(mask, next, curr).id;
1251 }
1252 return rhs;
1253}
1254
1255void SkVMGenerator::writeBlock(const Block& b) {
1256 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1257 this->writeStatement(*stmt);
1258 }
1259}
1260
1261void SkVMGenerator::writeIfStatement(const IfStatement& i) {
1262 Value test = this->writeExpression(*i.test());
1263 {
1264 AutoMask ifTrue(this, i32(test));
1265 this->writeStatement(*i.ifTrue());
1266 }
1267 if (i.ifFalse()) {
1268 AutoMask ifFalse(this, ~i32(test));
1269 this->writeStatement(*i.ifFalse());
1270 }
1271}
1272
1273void SkVMGenerator::writeReturnStatement(const ReturnStatement& r) {
1274 // TODO: Can we suppress other side effects for lanes that have returned? fMask needs to
1275 // fold in knowledge of conditional returns earlier in the function.
1276 skvm::I32 returnsHere = bit_clear(this->mask(), fReturned);
1277
1278 // TODO: returns with no expression
1279 Value val = this->writeExpression(*r.expression());
1280
1281 for (size_t i = 0; i < val.slots(); ++i) {
1282 fReturnValue[i] = select(returnsHere, f32(val[i]), f32(fReturnValue[i])).id;
1283 }
1284
1285 fReturned |= returnsHere;
1286}
1287
1288void SkVMGenerator::writeVarDeclaration(const VarDeclaration& decl) {
1289 Slot slot = this->getSlot(decl.var());
1290 size_t nslots = slot_count(decl.var().type());
1291
1292 Value val = decl.value() ? this->writeExpression(*decl.value()) : Value{};
1293 for (size_t i = 0; i < nslots; ++i) {
1294 fSlots[slot + i] = val ? val[i] : fBuilder->splat(0.0f).id;
1295 }
1296}
1297
1298void SkVMGenerator::writeStatement(const Statement& s) {
1299 switch (s.kind()) {
1300 case Statement::Kind::kBlock:
1301 this->writeBlock(s.as<Block>());
1302 break;
1303 case Statement::Kind::kExpression:
1304 this->writeExpression(*s.as<ExpressionStatement>().expression());
1305 break;
1306 case Statement::Kind::kIf:
1307 this->writeIfStatement(s.as<IfStatement>());
1308 break;
1309 case Statement::Kind::kReturn:
1310 this->writeReturnStatement(s.as<ReturnStatement>());
1311 break;
1312 case Statement::Kind::kVarDeclaration:
1313 this->writeVarDeclaration(s.as<VarDeclaration>());
1314 break;
1315 case Statement::Kind::kBreak:
1316 case Statement::Kind::kContinue:
1317 case Statement::Kind::kDiscard:
1318 case Statement::Kind::kDo:
1319 case Statement::Kind::kFor:
1320 case Statement::Kind::kSwitch:
1321 fErrors.error(s.fOffset, "Unsupported control flow");
1322 break;
1323 case Statement::Kind::kInlineMarker:
1324 case Statement::Kind::kNop:
1325 break;
1326 default:
1327 SkASSERT(false);
1328 }
1329}
1330
1331skvm::Color ProgramToSkVM(const Program& program,
1332 const FunctionDefinition& function,
1333 skvm::Builder* builder,
1334 SkSpan<skvm::Val> uniforms,
1335 skvm::Coord device,
1336 skvm::Coord local,
1337 SampleChildFn sampleChild) {
1338 DebugfErrorReporter errors;
1339
1340 skvm::Val params[2] = {local.x.id, local.y.id};
1341 skvm::Val result[4] = {skvm::NA, skvm::NA, skvm::NA, skvm::NA};
1342 size_t paramSlots = 0;
1343 for (const SkSL::Variable* param : function.declaration().parameters()) {
1344 paramSlots += slot_count(param->type());
1345 }
1346 SkASSERT(paramSlots <= SK_ARRAY_COUNT(params));
1347
1348 SkVMGenerator generator(program, function, builder, uniforms, {params, paramSlots},
1349 device, local, std::move(sampleChild), result, &errors);
1350
1351 return generator.generateCode() ? skvm::Color{{builder, result[0]},
1352 {builder, result[1]},
1353 {builder, result[2]},
1354 {builder, result[3]}}
1355 : skvm::Color{};
1356}
1357
Brian Osman47726a12020-12-17 16:02:08 -05001358/*
1359 * Testing utility function that emits program's "main" with a minimal harness. Used to create
1360 * representative skvm op sequences for SkSL tests.
1361 */
1362bool testingOnly_ProgramToSkVMShader(const Program& program, skvm::Builder* builder) {
1363 const SkSL::FunctionDefinition* main = nullptr;
1364 size_t uniformSlots = 0;
1365 int childSlots = 0;
1366 for (const SkSL::ProgramElement* e : program.elements()) {
1367 if (e->is<SkSL::FunctionDefinition>() &&
1368 e->as<SkSL::FunctionDefinition>().declaration().name() == "main") {
1369 main = &e->as<SkSL::FunctionDefinition>();
1370 }
1371 if (e->is<GlobalVarDeclaration>()) {
1372 const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
1373 const Variable& var = decl.declaration()->as<VarDeclaration>().var();
1374 if (var.type() == *program.fContext->fFragmentProcessor_Type) {
1375 childSlots++;
1376 } else if (is_uniform(var)) {
1377 uniformSlots += slot_count(var.type());
1378 }
1379 }
1380 }
1381 if (!main) { return false; }
Brian Osman0a442b72020-12-02 11:12:51 -05001382
Brian Osman47726a12020-12-17 16:02:08 -05001383 skvm::Uniforms uniforms(0);
1384 uniforms.base = builder->uniform();
1385
1386 auto new_uni = [&]() { return builder->uniformF(uniforms.pushF(0.0f)); };
1387
1388 // Assume identity CTM
1389 skvm::Coord device = {pun_to_F32(builder->index()), new_uni()};
1390 skvm::Coord local = device;
1391
1392 struct Child {
1393 skvm::Uniform addr;
1394 skvm::I32 rowBytesAsPixels;
1395 };
1396
1397 std::vector<Child> children;
1398 for (int i = 0; i < childSlots; ++i) {
1399 children.push_back({uniforms.pushPtr(nullptr), builder->uniform32(uniforms.push(0))});
1400 }
1401
1402 auto sampleChild = [&](int i, skvm::Coord coord) {
1403 skvm::PixelFormat pixelFormat;
1404 SkColorType_to_PixelFormat(kRGBA_F32_SkColorType, &pixelFormat);
1405 skvm::I32 index = trunc(coord.x) +
1406 trunc(coord.y) * children[i].rowBytesAsPixels;
1407 return gather(pixelFormat, children[i].addr, index);
1408 };
1409
1410 std::vector<skvm::Val> uniformVals;
1411 for (size_t i = 0; i < uniformSlots; ++i) {
1412 uniformVals.push_back(new_uni().id);
1413 }
1414
1415 skvm::Color result =
1416 SkSL::ProgramToSkVM(program, *main, builder, uniformVals, device, local, sampleChild);
1417
1418 storeF(builder->varying<float>(), result.r);
1419 storeF(builder->varying<float>(), result.g);
1420 storeF(builder->varying<float>(), result.b);
1421 storeF(builder->varying<float>(), result.a);
1422
1423 return true;
1424
1425}
1426
1427} // namespace SkSL