blob: c79dc5f11c2d2309ea89e9fb64c33daafcc727f3 [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),
710 dstKind = base_number_kind(dstType);
711 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
719 // TODO: Handle conversion to/from bool
720 // TODO: Handle signed vs. unsigned? GLSL ES 1.0 only has 'int', so no problem yet
721 if (srcKind != dstKind) {
722 // One argument constructors can do type conversion
723 Value dst(src.slots());
724 if (dstKind == Type::NumberKind::kFloat) {
725 SkASSERT(srcKind == Type::NumberKind::kSigned);
726 for (size_t i = 0; i < src.slots(); ++i) {
727 dst[i] = skvm::to_F32(i32(src[i]));
728 }
729 } else if (dstKind == Type::NumberKind::kSigned) {
730 SkASSERT(srcKind == Type::NumberKind::kFloat);
731 for (size_t i = 0; i < src.slots(); ++i) {
732 dst[i] = skvm::trunc(f32(src[i]));
733 }
734 } else {
735 SkDEBUGFAIL("Unsupported type conversion");
736 }
737 return dst;
738 }
739
740 // Matrices can be constructed from scalars or other matrices
741 if (dstType.isMatrix()) {
742 Value dst(dstType.rows() * dstType.columns());
743 size_t dstIndex = 0;
744 if (srcType.isMatrix()) {
745 // Matrix-from-matrix uses src where it overlaps, fills in missing with identity
746 for (int c = 0; c < dstType.columns(); ++c)
747 for (int r = 0; r < dstType.rows(); ++r) {
748 if (c < srcType.columns() && r < srcType.rows()) {
749 dst[dstIndex++] = src[c * srcType.rows() + r];
750 } else {
751 dst[dstIndex++] = fBuilder->splat(c == r ? 1.0f : 0.0f);
752 }
753 }
754 } else if (srcType.isScalar()) {
755 // Matrix-from-scalar builds a diagonal scale matrix
756 for (int c = 0; c < dstType.columns(); ++c)
757 for (int r = 0; r < dstType.rows(); ++r) {
758 dst[dstIndex++] = (c == r ? f32(src) : fBuilder->splat(0.0f));
759 }
760 } else {
761 SkDEBUGFAIL("Invalid matrix constructor");
762 }
763 SkASSERT(dstIndex == dst.slots());
764 return dst;
765 }
766
767 // We can splat scalars to all components of a vector
768 if (dstType.isVector() && srcType.isScalar()) {
769 Value dst(dstType.columns());
770 for (int i = 0; i < dstType.columns(); ++i) {
771 dst[i] = src[0];
772 }
773 return dst;
774 }
775
776 SkDEBUGFAIL("Invalid constructor");
777 return {};
778}
779
780Value SkVMGenerator::writeVariableExpression(const Expression& e) {
781 Slot slot = this->getSlot(e);
782 Value val(slot_count(e.type()));
783 for (size_t i = 0; i < val.slots(); ++i) {
784 val[i] = fSlots[slot + i];
785 }
786 return val;
787}
788
789Value SkVMGenerator::writeMatrixInverse2x2(const Value& m) {
790 SkASSERT(m.slots() == 4);
791 skvm::F32 a = f32(m[0]),
792 b = f32(m[1]),
793 c = f32(m[2]),
794 d = f32(m[3]);
795 skvm::F32 idet = 1.0f / (a*d - b*c);
796
797 Value result(m.slots());
798 result[0] = ( d * idet);
799 result[1] = (-b * idet);
800 result[2] = (-c * idet);
801 result[3] = ( a * idet);
802 return result;
803}
804
805Value SkVMGenerator::writeMatrixInverse3x3(const Value& m) {
806 SkASSERT(m.slots() == 9);
807 skvm::F32 a11 = f32(m[0]), a12 = f32(m[3]), a13 = f32(m[6]),
808 a21 = f32(m[1]), a22 = f32(m[4]), a23 = f32(m[7]),
809 a31 = f32(m[2]), a32 = f32(m[5]), a33 = f32(m[8]);
810 skvm::F32 idet = 1.0f / (a11*a22*a33 + a12*a23*a31 + a13*a21*a32 -
811 a11*a23*a32 - a12*a21*a33 - a13*a22*a31);
812
813 Value result(m.slots());
814 result[0] = ((a22*a33 - a23*a32) * idet);
815 result[1] = ((a23*a31 - a21*a33) * idet);
816 result[2] = ((a21*a32 - a22*a31) * idet);
817 result[3] = ((a13*a32 - a12*a33) * idet);
818 result[4] = ((a11*a33 - a13*a31) * idet);
819 result[5] = ((a12*a31 - a11*a32) * idet);
820 result[6] = ((a12*a23 - a13*a22) * idet);
821 result[7] = ((a13*a21 - a11*a23) * idet);
822 result[8] = ((a11*a22 - a12*a21) * idet);
823 return result;
824}
825
826Value SkVMGenerator::writeMatrixInverse4x4(const Value& m) {
827 SkASSERT(m.slots() == 16);
828 skvm::F32 a00 = f32(m[0]), a10 = f32(m[4]), a20 = f32(m[ 8]), a30 = f32(m[12]),
829 a01 = f32(m[1]), a11 = f32(m[5]), a21 = f32(m[ 9]), a31 = f32(m[13]),
830 a02 = f32(m[2]), a12 = f32(m[6]), a22 = f32(m[10]), a32 = f32(m[14]),
831 a03 = f32(m[3]), a13 = f32(m[7]), a23 = f32(m[11]), a33 = f32(m[15]);
832
833 skvm::F32 b00 = a00*a11 - a01*a10,
834 b01 = a00*a12 - a02*a10,
835 b02 = a00*a13 - a03*a10,
836 b03 = a01*a12 - a02*a11,
837 b04 = a01*a13 - a03*a11,
838 b05 = a02*a13 - a03*a12,
839 b06 = a20*a31 - a21*a30,
840 b07 = a20*a32 - a22*a30,
841 b08 = a20*a33 - a23*a30,
842 b09 = a21*a32 - a22*a31,
843 b10 = a21*a33 - a23*a31,
844 b11 = a22*a33 - a23*a32;
845
846 skvm::F32 idet = 1.0f / (b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
847
848 b00 *= idet;
849 b01 *= idet;
850 b02 *= idet;
851 b03 *= idet;
852 b04 *= idet;
853 b05 *= idet;
854 b06 *= idet;
855 b07 *= idet;
856 b08 *= idet;
857 b09 *= idet;
858 b10 *= idet;
859 b11 *= idet;
860
861 Value result(m.slots());
862 result[ 0] = (a11*b11 - a12*b10 + a13*b09);
863 result[ 1] = (a02*b10 - a01*b11 - a03*b09);
864 result[ 2] = (a31*b05 - a32*b04 + a33*b03);
865 result[ 3] = (a22*b04 - a21*b05 - a23*b03);
866 result[ 4] = (a12*b08 - a10*b11 - a13*b07);
867 result[ 5] = (a00*b11 - a02*b08 + a03*b07);
868 result[ 6] = (a32*b02 - a30*b05 - a33*b01);
869 result[ 7] = (a20*b05 - a22*b02 + a23*b01);
870 result[ 8] = (a10*b10 - a11*b08 + a13*b06);
871 result[ 9] = (a01*b08 - a00*b10 - a03*b06);
872 result[10] = (a30*b04 - a31*b02 + a33*b00);
873 result[11] = (a21*b02 - a20*b04 - a23*b00);
874 result[12] = (a11*b07 - a10*b09 - a12*b06);
875 result[13] = (a00*b09 - a01*b07 + a02*b06);
876 result[14] = (a31*b01 - a30*b03 - a32*b00);
877 result[15] = (a20*b03 - a21*b01 + a22*b00);
878 return result;
879}
880
881Value SkVMGenerator::writeIntrinsicCall(const FunctionCall& c) {
882 auto found = fIntrinsics.find(c.function().name());
883 if (found == fIntrinsics.end()) {
Brian Osman47726a12020-12-17 16:02:08 -0500884 SkDEBUGFAILF("Missing intrinsic: '%s'", String(c.function().name()).c_str());
Brian Osman0a442b72020-12-02 11:12:51 -0500885 return {};
886 }
887
888 const size_t nargs = c.arguments().size();
889
890 if (found->second == Intrinsic::kSample) {
891 // Sample is very special, the first argument is an FP, which can't be evaluated
892 const Context& ctx = *fProgram.fContext;
893 if (nargs > 2 || c.arguments()[0]->type() != *ctx.fFragmentProcessor_Type ||
894 (nargs == 2 && (c.arguments()[1]->type() != *ctx.fFloat2_Type &&
895 c.arguments()[1]->type() != *ctx.fFloat3x3_Type))) {
896 SkDEBUGFAIL("Invalid call to sample");
897 return {};
898 }
899
900 auto fp_it = fVariableMap.find(c.arguments()[0]->as<VariableReference>().variable());
901 SkASSERT(fp_it != fVariableMap.end());
902
903 skvm::Coord coord = fLocalCoord;
904 if (nargs == 2) {
905 Value arg = this->writeExpression(*c.arguments()[1]);
906 if (arg.slots() == 2) {
907 // explicit sampling
908 coord = {f32(arg[0]), f32(arg[1])};
909 } else {
910 // matrix sampling
911 SkASSERT(arg.slots() == 9);
912 skvm::F32 x = f32(arg[0])*coord.x + f32(arg[3])*coord.y + f32(arg[6]),
913 y = f32(arg[1])*coord.x + f32(arg[4])*coord.y + f32(arg[7]),
914 w = f32(arg[2])*coord.x + f32(arg[5])*coord.y + f32(arg[8]);
915 x = x * (1.0f / w);
916 y = y * (1.0f / w);
917 coord = {x, y};
918 }
919 }
920
921 skvm::Color color = fSampleChild(fp_it->second, coord);
922 Value result(4);
923 result[0] = color.r;
924 result[1] = color.g;
925 result[2] = color.b;
926 result[3] = color.a;
927 return result;
928 }
929
930 const size_t kMaxArgs = 3; // eg: clamp, mix, smoothstep
931 Value args[kMaxArgs];
932 SkASSERT(nargs >= 1 && nargs <= SK_ARRAY_COUNT(args));
933
934 // All other intrinsics have at most three args, and those can all be evaluated up front:
935 for (size_t i = 0; i < nargs; ++i) {
936 args[i] = this->writeExpression(*c.arguments()[i]);
937 }
938 Type::NumberKind nk = base_number_kind(c.arguments()[0]->type());
939
940 auto binary = [&](auto&& fn) {
941 // Binary intrinsics are (vecN, vecN), (vecN, float), or (float, vecN)
942 size_t nslots = std::max(args[0].slots(), args[1].slots());
943 Value result(nslots);
944 SkASSERT(args[0].slots() == nslots || args[0].slots() == 1);
945 SkASSERT(args[1].slots() == nslots || args[1].slots() == 1);
946
947 for (size_t i = 0; i < nslots; ++i) {
948 result[i] = fn({fBuilder, args[0][args[0].slots() == 1 ? 0 : i]},
949 {fBuilder, args[1][args[1].slots() == 1 ? 0 : i]});
950 }
951 return result;
952 };
953
954 auto ternary = [&](auto&& fn) {
955 // Ternary intrinsics are some combination of vecN and float
956 size_t nslots = std::max({args[0].slots(), args[1].slots(), args[2].slots()});
957 Value result(nslots);
958 SkASSERT(args[0].slots() == nslots || args[0].slots() == 1);
959 SkASSERT(args[1].slots() == nslots || args[1].slots() == 1);
960 SkASSERT(args[2].slots() == nslots || args[2].slots() == 1);
961
962 for (size_t i = 0; i < nslots; ++i) {
963 result[i] = fn({fBuilder, args[0][args[0].slots() == 1 ? 0 : i]},
964 {fBuilder, args[1][args[1].slots() == 1 ? 0 : i]},
965 {fBuilder, args[2][args[2].slots() == 1 ? 0 : i]});
966 }
967 return result;
968 };
969
970 auto dot = [&](const Value& x, const Value& y) {
971 SkASSERT(x.slots() == y.slots());
972 skvm::F32 result = f32(x[0]) * f32(y[0]);
973 for (size_t i = 1; i < x.slots(); ++i) {
974 result += f32(x[i]) * f32(y[i]);
975 }
976 return result;
977 };
978
979 switch (found->second) {
980 case Intrinsic::kSin: return unary(args[0], skvm::approx_sin);
981 case Intrinsic::kCos: return unary(args[0], skvm::approx_cos);
982 case Intrinsic::kTan: return unary(args[0], skvm::approx_tan);
983
984 case Intrinsic::kASin: return unary(args[0], skvm::approx_asin);
985 case Intrinsic::kACos: return unary(args[0], skvm::approx_acos);
986
987 case Intrinsic::kATan: return nargs == 1 ? unary(args[0], skvm::approx_atan)
988 : binary(skvm::approx_atan2);
989
990 case Intrinsic::kPow:
991 return binary([](skvm::F32 x, skvm::F32 y) { return skvm::approx_powf(x, y); });
992 case Intrinsic::kExp: return unary(args[0], skvm::approx_exp);
993 case Intrinsic::kLog: return unary(args[0], skvm::approx_log);
994 case Intrinsic::kExp2: return unary(args[0], skvm::approx_pow2);
995 case Intrinsic::kLog2: return unary(args[0], skvm::approx_log2);
996
997 case Intrinsic::kSqrt: return unary(args[0], skvm::sqrt);
998 case Intrinsic::kInverseSqrt:
999 return unary(args[0], [](skvm::F32 x) { return 1.0f / skvm::sqrt(x); });
1000
1001 case Intrinsic::kAbs: return unary(args[0], skvm::abs);
1002 case Intrinsic::kSign:
1003 return unary(args[0], [](skvm::F32 x) { return select(x < 0, -1.0f,
1004 select(x > 0, +1.0f, 0.0f)); });
1005 case Intrinsic::kFloor: return unary(args[0], skvm::floor);
1006 case Intrinsic::kCeil: return unary(args[0], skvm::ceil);
1007 case Intrinsic::kFract: return unary(args[0], skvm::fract);
1008 case Intrinsic::kMod:
1009 return binary([](skvm::F32 x, skvm::F32 y) { return x - y*skvm::floor(x / y); });
1010
1011 case Intrinsic::kMin:
1012 return binary([](skvm::F32 x, skvm::F32 y) { return skvm::min(x, y); });
1013 case Intrinsic::kMax:
1014 return binary([](skvm::F32 x, skvm::F32 y) { return skvm::max(x, y); });
1015 case Intrinsic::kClamp:
1016 return ternary(
1017 [](skvm::F32 x, skvm::F32 lo, skvm::F32 hi) { return skvm::clamp(x, lo, hi); });
1018 case Intrinsic::kSaturate:
1019 return unary(args[0], [](skvm::F32 x) { return skvm::clamp01(x); });
1020 case Intrinsic::kMix:
1021 return ternary(
1022 [](skvm::F32 x, skvm::F32 y, skvm::F32 t) { return skvm::lerp(x, y, t); });
1023 case Intrinsic::kStep:
1024 return binary([](skvm::F32 edge, skvm::F32 x) { return select(x < edge, 0.0f, 1.0f); });
1025 case Intrinsic::kSmoothstep:
1026 return ternary([](skvm::F32 edge0, skvm::F32 edge1, skvm::F32 x) {
1027 skvm::F32 t = skvm::clamp01((x - edge0) / (edge1 - edge0));
1028 return t * t * (3 - 2 * t);
1029 });
1030
1031 case Intrinsic::kLength: return skvm::sqrt(dot(args[0], args[0]));
1032 case Intrinsic::kDistance: {
1033 Value vec = binary([](skvm::F32 x, skvm::F32 y) { return x - y; });
1034 return skvm::sqrt(dot(vec, vec));
1035 }
1036 case Intrinsic::kDot: return dot(args[0], args[1]);
1037 case Intrinsic::kNormalize: {
1038 skvm::F32 invLen = 1.0f / skvm::sqrt(dot(args[0], args[0]));
1039 return unary(args[0], [&](skvm::F32 x) { return x * invLen; });
1040 }
1041
Brian Osman93aed9a2020-12-28 15:18:46 -05001042 case Intrinsic::kMatrixCompMult:
1043 return binary([](skvm::F32 x, skvm::F32 y) { return x * y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001044 case Intrinsic::kInverse: {
1045 switch (args[0].slots()) {
1046 case 4: return this->writeMatrixInverse2x2(args[0]);
1047 case 9: return this->writeMatrixInverse3x3(args[0]);
1048 case 16: return this->writeMatrixInverse4x4(args[0]);
1049 default:
1050 SkDEBUGFAIL("Invalid call to inverse");
1051 return {};
1052 }
1053 }
1054
1055 case Intrinsic::kLessThan:
Brian Osman30b67292020-12-23 13:02:09 -05001056 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; });
Brian Osman0a442b72020-12-02 11:12:51 -05001059 case Intrinsic::kLessThanEqual:
Brian Osman30b67292020-12-23 13:02:09 -05001060 return nk == Type::NumberKind::kFloat
1061 ? binary([](skvm::F32 x, skvm::F32 y) { return x <= y; })
1062 : binary([](skvm::I32 x, skvm::I32 y) { return x <= y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001063 case Intrinsic::kGreaterThan:
Brian Osman30b67292020-12-23 13:02:09 -05001064 return nk == Type::NumberKind::kFloat
1065 ? binary([](skvm::F32 x, skvm::F32 y) { return x > y; })
1066 : binary([](skvm::I32 x, skvm::I32 y) { return x > y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001067 case Intrinsic::kGreaterThanEqual:
Brian Osman30b67292020-12-23 13:02:09 -05001068 return nk == Type::NumberKind::kFloat
1069 ? binary([](skvm::F32 x, skvm::F32 y) { return x >= y; })
1070 : binary([](skvm::I32 x, skvm::I32 y) { return x >= y; });
Brian Osman0a442b72020-12-02 11:12:51 -05001071
1072 case Intrinsic::kEqual:
1073 return nk == Type::NumberKind::kFloat
1074 ? binary([](skvm::F32 x, skvm::F32 y) { return x == y; })
1075 : binary([](skvm::I32 x, skvm::I32 y) { return x == y; });
1076 case Intrinsic::kNotEqual:
1077 return nk == Type::NumberKind::kFloat
1078 ? binary([](skvm::F32 x, skvm::F32 y) { return x != y; })
1079 : binary([](skvm::I32 x, skvm::I32 y) { return x != y; });
1080
1081 case Intrinsic::kAny: {
1082 skvm::I32 result = i32(args[0][0]);
1083 for (size_t i = 1; i < args[0].slots(); ++i) {
1084 result |= i32(args[0][i]);
1085 }
1086 return result;
1087 }
1088 case Intrinsic::kAll: {
1089 skvm::I32 result = i32(args[0][0]);
1090 for (size_t i = 1; i < args[0].slots(); ++i) {
1091 result &= i32(args[0][i]);
1092 }
1093 return result;
1094 }
1095 case Intrinsic::kNot: return unary(args[0], [](skvm::I32 x) { return ~x; });
1096
1097 case Intrinsic::kSample:
1098 // Handled earlier
1099 SkASSERT(false);
1100 return {};
1101 }
1102 SkUNREACHABLE;
1103}
1104
1105Value SkVMGenerator::writeFunctionCall(const FunctionCall& f) {
1106 // TODO: Support calling other functions (by recursively generating their programs, eg inlining)
1107 if (f.function().isBuiltin()) {
1108 return this->writeIntrinsicCall(f);
1109 }
1110
1111 fErrors.error(-1, "Function calls not supported yet");
1112 return {};
1113}
1114
1115Value SkVMGenerator::writePrefixExpression(const PrefixExpression& p) {
1116 Value val = this->writeExpression(*p.operand());
1117
1118 switch (p.getOperator()) {
1119 case Token::Kind::TK_PLUSPLUS:
1120 case Token::Kind::TK_MINUSMINUS: {
1121 bool incr = p.getOperator() == Token::Kind::TK_PLUSPLUS;
1122
1123 switch (base_number_kind(p.type())) {
1124 case Type::NumberKind::kFloat:
1125 val = f32(val) + fBuilder->splat(incr ? 1.0f : -1.0f);
1126 break;
1127 case Type::NumberKind::kSigned:
1128 val = i32(val) + fBuilder->splat(incr ? 1 : -1);
1129 break;
1130 default:
1131 SkASSERT(false);
1132 return {};
1133 }
1134 return this->writeStore(*p.operand(), val);
1135 }
1136 case Token::Kind::TK_MINUS: {
1137 switch (base_number_kind(p.type())) {
1138 case Type::NumberKind::kFloat:
1139 return this->unary(val, [](skvm::F32 x) { return -x; });
1140 case Type::NumberKind::kSigned:
1141 return this->unary(val, [](skvm::I32 x) { return -x; });
1142 default:
1143 SkASSERT(false);
1144 return {};
1145 }
1146 }
1147 case Token::Kind::TK_LOGICALNOT:
1148 case Token::Kind::TK_BITWISENOT:
1149 return this->unary(val, [](skvm::I32 x) { return ~x; });
1150 default:
1151 SkASSERT(false);
1152 return {};
1153 }
1154}
1155
1156Value SkVMGenerator::writePostfixExpression(const PostfixExpression& p) {
1157 switch (p.getOperator()) {
1158 case Token::Kind::TK_PLUSPLUS:
1159 case Token::Kind::TK_MINUSMINUS: {
1160 Value old = this->writeExpression(*p.operand()),
1161 val = old;
1162 SkASSERT(val.slots() == 1);
1163 bool incr = p.getOperator() == Token::Kind::TK_PLUSPLUS;
1164
1165 switch (base_number_kind(p.type())) {
1166 case Type::NumberKind::kFloat:
1167 val = f32(val) + fBuilder->splat(incr ? 1.0f : -1.0f);
1168 break;
1169 case Type::NumberKind::kSigned:
1170 val = i32(val) + fBuilder->splat(incr ? 1 : -1);
1171 break;
1172 default:
1173 SkASSERT(false);
1174 return {};
1175 }
1176 this->writeStore(*p.operand(), val);
1177 return old;
1178 }
1179 default:
1180 SkASSERT(false);
1181 return {};
1182 }
1183}
1184
1185Value SkVMGenerator::writeSwizzle(const Swizzle& s) {
1186 Value base = this->writeExpression(*s.base());
1187 Value swizzled(s.components().size());
1188 for (size_t i = 0; i < s.components().size(); ++i) {
1189 swizzled[i] = base[s.components()[i]];
1190 }
1191 return swizzled;
1192}
1193
1194Value SkVMGenerator::writeTernaryExpression(const TernaryExpression& t) {
1195 skvm::I32 test = i32(this->writeExpression(*t.test()));
1196 Value ifTrue, ifFalse;
1197
1198 {
1199 AutoMask m(this, test);
1200 ifTrue = this->writeExpression(*t.ifTrue());
1201 }
1202 {
1203 AutoMask m(this, ~test);
1204 ifFalse = this->writeExpression(*t.ifFalse());
1205 }
1206
1207 size_t nslots = ifTrue.slots();
1208 SkASSERT(nslots == ifFalse.slots());
1209
1210 Value result(nslots);
1211 for (size_t i = 0; i < nslots; ++i) {
1212 result[i] = skvm::select(test, i32(ifTrue[i]), i32(ifFalse[i]));
1213 }
1214 return result;
1215}
1216
1217Value SkVMGenerator::writeExpression(const Expression& e) {
1218 switch (e.kind()) {
1219 case Expression::Kind::kBinary:
1220 return this->writeBinaryExpression(e.as<BinaryExpression>());
1221 case Expression::Kind::kBoolLiteral:
1222 return fBuilder->splat(e.as<BoolLiteral>().value() ? ~0 : 0);
1223 case Expression::Kind::kConstructor:
1224 return this->writeConstructor(e.as<Constructor>());
1225 case Expression::Kind::kFieldAccess:
1226 case Expression::Kind::kIndex:
1227 case Expression::Kind::kVariableReference:
1228 return this->writeVariableExpression(e);
1229 case Expression::Kind::kFloatLiteral:
1230 return fBuilder->splat(e.as<FloatLiteral>().value());
1231 case Expression::Kind::kFunctionCall:
1232 return this->writeFunctionCall(e.as<FunctionCall>());
1233 case Expression::Kind::kIntLiteral:
1234 return fBuilder->splat(static_cast<int>(e.as<IntLiteral>().value()));
Brian Osman0a442b72020-12-02 11:12:51 -05001235 case Expression::Kind::kPrefix:
1236 return this->writePrefixExpression(e.as<PrefixExpression>());
1237 case Expression::Kind::kPostfix:
1238 return this->writePostfixExpression(e.as<PostfixExpression>());
1239 case Expression::Kind::kSwizzle:
1240 return this->writeSwizzle(e.as<Swizzle>());
1241 case Expression::Kind::kTernary:
1242 return this->writeTernaryExpression(e.as<TernaryExpression>());
1243 case Expression::Kind::kExternalFunctionCall:
1244 case Expression::Kind::kExternalValue:
1245 default:
1246 SkDEBUGFAIL("Unsupported expression");
1247 return {};
1248 }
1249}
1250
1251Value SkVMGenerator::writeStore(const Expression& lhs, const Value& rhs) {
1252 SkASSERT(lhs.is<FieldAccess>() || lhs.is<IndexExpression>() || lhs.is<Swizzle>() ||
1253 lhs.is<VariableReference>());
1254 SkASSERT(rhs.slots() == slot_count(lhs.type()));
1255
1256 skvm::I32 mask = this->mask();
1257 for (size_t i = rhs.slots(); i --> 0;) {
1258 const Expression* expr = &lhs;
1259 int component = i;
1260 while (expr->is<Swizzle>()) {
1261 component = expr->as<Swizzle>().components()[component];
1262 expr = expr->as<Swizzle>().base().get();
1263 }
1264 Slot slot = this->getSlot(*expr);
1265 skvm::F32 curr = f32(fSlots[slot + component]),
1266 next = f32(rhs[i]);
1267 fSlots[slot + component] = select(mask, next, curr).id;
1268 }
1269 return rhs;
1270}
1271
1272void SkVMGenerator::writeBlock(const Block& b) {
1273 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1274 this->writeStatement(*stmt);
1275 }
1276}
1277
1278void SkVMGenerator::writeIfStatement(const IfStatement& i) {
1279 Value test = this->writeExpression(*i.test());
1280 {
1281 AutoMask ifTrue(this, i32(test));
1282 this->writeStatement(*i.ifTrue());
1283 }
1284 if (i.ifFalse()) {
1285 AutoMask ifFalse(this, ~i32(test));
1286 this->writeStatement(*i.ifFalse());
1287 }
1288}
1289
1290void SkVMGenerator::writeReturnStatement(const ReturnStatement& r) {
1291 // TODO: Can we suppress other side effects for lanes that have returned? fMask needs to
1292 // fold in knowledge of conditional returns earlier in the function.
1293 skvm::I32 returnsHere = bit_clear(this->mask(), fReturned);
1294
1295 // TODO: returns with no expression
1296 Value val = this->writeExpression(*r.expression());
1297
1298 for (size_t i = 0; i < val.slots(); ++i) {
1299 fReturnValue[i] = select(returnsHere, f32(val[i]), f32(fReturnValue[i])).id;
1300 }
1301
1302 fReturned |= returnsHere;
1303}
1304
1305void SkVMGenerator::writeVarDeclaration(const VarDeclaration& decl) {
1306 Slot slot = this->getSlot(decl.var());
1307 size_t nslots = slot_count(decl.var().type());
1308
1309 Value val = decl.value() ? this->writeExpression(*decl.value()) : Value{};
1310 for (size_t i = 0; i < nslots; ++i) {
1311 fSlots[slot + i] = val ? val[i] : fBuilder->splat(0.0f).id;
1312 }
1313}
1314
1315void SkVMGenerator::writeStatement(const Statement& s) {
1316 switch (s.kind()) {
1317 case Statement::Kind::kBlock:
1318 this->writeBlock(s.as<Block>());
1319 break;
1320 case Statement::Kind::kExpression:
1321 this->writeExpression(*s.as<ExpressionStatement>().expression());
1322 break;
1323 case Statement::Kind::kIf:
1324 this->writeIfStatement(s.as<IfStatement>());
1325 break;
1326 case Statement::Kind::kReturn:
1327 this->writeReturnStatement(s.as<ReturnStatement>());
1328 break;
1329 case Statement::Kind::kVarDeclaration:
1330 this->writeVarDeclaration(s.as<VarDeclaration>());
1331 break;
1332 case Statement::Kind::kBreak:
1333 case Statement::Kind::kContinue:
1334 case Statement::Kind::kDiscard:
1335 case Statement::Kind::kDo:
1336 case Statement::Kind::kFor:
1337 case Statement::Kind::kSwitch:
1338 fErrors.error(s.fOffset, "Unsupported control flow");
1339 break;
1340 case Statement::Kind::kInlineMarker:
1341 case Statement::Kind::kNop:
1342 break;
1343 default:
1344 SkASSERT(false);
1345 }
1346}
1347
1348skvm::Color ProgramToSkVM(const Program& program,
1349 const FunctionDefinition& function,
1350 skvm::Builder* builder,
1351 SkSpan<skvm::Val> uniforms,
1352 skvm::Coord device,
1353 skvm::Coord local,
1354 SampleChildFn sampleChild) {
1355 DebugfErrorReporter errors;
1356
Brian Osman5933d4c2021-01-05 13:02:20 -05001357 skvm::Val args[2] = {local.x.id, local.y.id};
Brian Osman0a442b72020-12-02 11:12:51 -05001358 skvm::Val result[4] = {skvm::NA, skvm::NA, skvm::NA, skvm::NA};
1359 size_t paramSlots = 0;
1360 for (const SkSL::Variable* param : function.declaration().parameters()) {
1361 paramSlots += slot_count(param->type());
1362 }
Brian Osman5933d4c2021-01-05 13:02:20 -05001363 SkASSERT(paramSlots <= SK_ARRAY_COUNT(args));
Brian Osman0a442b72020-12-02 11:12:51 -05001364
Brian Osman5933d4c2021-01-05 13:02:20 -05001365 SkVMGenerator generator(program, function, builder, uniforms, {args, paramSlots},
Brian Osman0a442b72020-12-02 11:12:51 -05001366 device, local, std::move(sampleChild), result, &errors);
1367
1368 return generator.generateCode() ? skvm::Color{{builder, result[0]},
1369 {builder, result[1]},
1370 {builder, result[2]},
1371 {builder, result[3]}}
1372 : skvm::Color{};
1373}
1374
Brian Osman5933d4c2021-01-05 13:02:20 -05001375const FunctionDefinition* Program_GetFunction(const Program& program, const char* function) {
1376 for (const ProgramElement* e : program.elements()) {
1377 if (e->is<FunctionDefinition>() &&
1378 e->as<FunctionDefinition>().declaration().name() == function) {
1379 return &e->as<FunctionDefinition>();
1380 }
1381 }
1382 return nullptr;
1383}
1384
Brian Osman47726a12020-12-17 16:02:08 -05001385/*
1386 * Testing utility function that emits program's "main" with a minimal harness. Used to create
1387 * representative skvm op sequences for SkSL tests.
1388 */
1389bool testingOnly_ProgramToSkVMShader(const Program& program, skvm::Builder* builder) {
Brian Osman5933d4c2021-01-05 13:02:20 -05001390 const SkSL::FunctionDefinition* main = Program_GetFunction(program, "main");
1391 if (!main) {
1392 return false;
1393 }
1394
Brian Osman47726a12020-12-17 16:02:08 -05001395 size_t uniformSlots = 0;
1396 int childSlots = 0;
1397 for (const SkSL::ProgramElement* e : program.elements()) {
Brian Osman47726a12020-12-17 16:02:08 -05001398 if (e->is<GlobalVarDeclaration>()) {
1399 const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
1400 const Variable& var = decl.declaration()->as<VarDeclaration>().var();
1401 if (var.type() == *program.fContext->fFragmentProcessor_Type) {
1402 childSlots++;
1403 } else if (is_uniform(var)) {
1404 uniformSlots += slot_count(var.type());
1405 }
1406 }
1407 }
Brian Osman0a442b72020-12-02 11:12:51 -05001408
Brian Osman47726a12020-12-17 16:02:08 -05001409 skvm::Uniforms uniforms(0);
1410 uniforms.base = builder->uniform();
1411
1412 auto new_uni = [&]() { return builder->uniformF(uniforms.pushF(0.0f)); };
1413
1414 // Assume identity CTM
1415 skvm::Coord device = {pun_to_F32(builder->index()), new_uni()};
1416 skvm::Coord local = device;
1417
1418 struct Child {
1419 skvm::Uniform addr;
1420 skvm::I32 rowBytesAsPixels;
1421 };
1422
1423 std::vector<Child> children;
1424 for (int i = 0; i < childSlots; ++i) {
1425 children.push_back({uniforms.pushPtr(nullptr), builder->uniform32(uniforms.push(0))});
1426 }
1427
1428 auto sampleChild = [&](int i, skvm::Coord coord) {
1429 skvm::PixelFormat pixelFormat;
1430 SkColorType_to_PixelFormat(kRGBA_F32_SkColorType, &pixelFormat);
1431 skvm::I32 index = trunc(coord.x) +
1432 trunc(coord.y) * children[i].rowBytesAsPixels;
1433 return gather(pixelFormat, children[i].addr, index);
1434 };
1435
1436 std::vector<skvm::Val> uniformVals;
1437 for (size_t i = 0; i < uniformSlots; ++i) {
1438 uniformVals.push_back(new_uni().id);
1439 }
1440
1441 skvm::Color result =
1442 SkSL::ProgramToSkVM(program, *main, builder, uniformVals, device, local, sampleChild);
1443
1444 storeF(builder->varying<float>(), result.r);
1445 storeF(builder->varying<float>(), result.g);
1446 storeF(builder->varying<float>(), result.b);
1447 storeF(builder->varying<float>(), result.a);
1448
1449 return true;
1450
1451}
1452
1453} // namespace SkSL