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