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