• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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/SkSLProgramElement.h"
9 #include "include/private/SkSLStatement.h"
10 #include "include/private/SkTArray.h"
11 #include "include/private/SkTPin.h"
12 #include "src/sksl/SkSLCompiler.h"
13 #include "src/sksl/SkSLOperators.h"
14 #include "src/sksl/codegen/SkSLCodeGenerator.h"
15 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
16 #include "src/sksl/ir/SkSLBinaryExpression.h"
17 #include "src/sksl/ir/SkSLBlock.h"
18 #include "src/sksl/ir/SkSLBreakStatement.h"
19 #include "src/sksl/ir/SkSLChildCall.h"
20 #include "src/sksl/ir/SkSLConstructor.h"
21 #include "src/sksl/ir/SkSLConstructorArray.h"
22 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
23 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
24 #include "src/sksl/ir/SkSLConstructorMatrixResize.h"
25 #include "src/sksl/ir/SkSLConstructorSplat.h"
26 #include "src/sksl/ir/SkSLConstructorStruct.h"
27 #include "src/sksl/ir/SkSLContinueStatement.h"
28 #include "src/sksl/ir/SkSLDoStatement.h"
29 #include "src/sksl/ir/SkSLExpressionStatement.h"
30 #include "src/sksl/ir/SkSLExternalFunctionCall.h"
31 #include "src/sksl/ir/SkSLExternalFunctionReference.h"
32 #include "src/sksl/ir/SkSLFieldAccess.h"
33 #include "src/sksl/ir/SkSLForStatement.h"
34 #include "src/sksl/ir/SkSLFunctionCall.h"
35 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
36 #include "src/sksl/ir/SkSLFunctionDefinition.h"
37 #include "src/sksl/ir/SkSLIfStatement.h"
38 #include "src/sksl/ir/SkSLIndexExpression.h"
39 #include "src/sksl/ir/SkSLLiteral.h"
40 #include "src/sksl/ir/SkSLPostfixExpression.h"
41 #include "src/sksl/ir/SkSLPrefixExpression.h"
42 #include "src/sksl/ir/SkSLReturnStatement.h"
43 #include "src/sksl/ir/SkSLSwitchStatement.h"
44 #include "src/sksl/ir/SkSLSwizzle.h"
45 #include "src/sksl/ir/SkSLTernaryExpression.h"
46 #include "src/sksl/ir/SkSLVarDeclarations.h"
47 #include "src/sksl/ir/SkSLVariableReference.h"
48 #include "src/sksl/tracing/SkVMDebugTrace.h"
49 
50 #include <algorithm>
51 #include <unordered_map>
52 
53 namespace {
54     // sksl allows the optimizations of fast_mul(), so we want to use that most of the time.
55     // This little sneaky snippet of code lets us use ** as a fast multiply infix operator.
56     struct FastF32 { skvm::F32 val; };
operator *(skvm::F32 y)57     static FastF32 operator*(skvm::F32 y) { return {y}; }
operator *(skvm::F32 x,FastF32 y)58     static skvm::F32 operator*(skvm::F32 x, FastF32 y) { return fast_mul(x, y.val); }
operator *(float x,FastF32 y)59     static skvm::F32 operator*(float     x, FastF32 y) { return fast_mul(x, y.val); }
60 
61     class SkSLTracer : public skvm::TraceHook {
62     public:
Make(SkSL::SkVMDebugTrace * trace)63         static std::unique_ptr<SkSLTracer> Make(SkSL::SkVMDebugTrace* trace) {
64             auto hook = std::make_unique<SkSLTracer>();
65             hook->fTrace = trace;
66             return hook;
67         }
68 
line(int lineNum)69         void line(int lineNum) override {
70             fTrace->fTraceInfo.push_back({SkSL::SkVMTraceInfo::Op::kLine,
71                                           /*data=*/{lineNum, 0}});
72         }
var(int slot,int32_t val)73         void var(int slot, int32_t val) override {
74             fTrace->fTraceInfo.push_back({SkSL::SkVMTraceInfo::Op::kVar,
75                                           /*data=*/{slot, val}});
76         }
enter(int fnIdx)77         void enter(int fnIdx) override {
78             fTrace->fTraceInfo.push_back({SkSL::SkVMTraceInfo::Op::kEnter,
79                                           /*data=*/{fnIdx, 0}});
80         }
exit(int fnIdx)81         void exit(int fnIdx) override {
82             fTrace->fTraceInfo.push_back({SkSL::SkVMTraceInfo::Op::kExit,
83                                           /*data=*/{fnIdx, 0}});
84         }
scope(int delta)85         void scope(int delta) override {
86             fTrace->fTraceInfo.push_back({SkSL::SkVMTraceInfo::Op::kScope,
87                                           /*data=*/{delta, 0}});
88         }
89 
90     private:
91         SkSL::SkVMDebugTrace* fTrace;
92     };
93 }  // namespace
94 
95 namespace SkSL {
96 
97 namespace {
98 
99 // Holds scalars, vectors, or matrices
100 struct Value {
101     Value() = default;
ValueSkSL::__anonf8b5168e0211::Value102     explicit Value(size_t slots) {
103         fVals.resize(slots);
104     }
ValueSkSL::__anonf8b5168e0211::Value105     Value(skvm::F32 x) : fVals({ x.id }) {}
ValueSkSL::__anonf8b5168e0211::Value106     Value(skvm::I32 x) : fVals({ x.id }) {}
107 
operator boolSkSL::__anonf8b5168e0211::Value108     explicit operator bool() const { return !fVals.empty(); }
109 
slotsSkSL::__anonf8b5168e0211::Value110     size_t slots() const { return fVals.size(); }
111 
112     struct ValRef {
ValRefSkSL::__anonf8b5168e0211::Value::ValRef113         ValRef(skvm::Val& val) : fVal(val) {}
114 
operator =SkSL::__anonf8b5168e0211::Value::ValRef115         ValRef& operator=(ValRef    v) { fVal = v.fVal; return *this; }
operator =SkSL::__anonf8b5168e0211::Value::ValRef116         ValRef& operator=(skvm::Val v) { fVal = v;      return *this; }
operator =SkSL::__anonf8b5168e0211::Value::ValRef117         ValRef& operator=(skvm::F32 v) { fVal = v.id;   return *this; }
operator =SkSL::__anonf8b5168e0211::Value::ValRef118         ValRef& operator=(skvm::I32 v) { fVal = v.id;   return *this; }
119 
operator skvm::ValSkSL::__anonf8b5168e0211::Value::ValRef120         operator skvm::Val() { return fVal; }
121 
122         skvm::Val& fVal;
123     };
124 
operator []SkSL::__anonf8b5168e0211::Value125     ValRef    operator[](size_t i) {
126         // These redundant asserts work around what we think is a codegen bug in GCC 8.x for
127         // 32-bit x86 Debug builds.
128         SkASSERT(i < fVals.size());
129         return fVals[i];
130     }
operator []SkSL::__anonf8b5168e0211::Value131     skvm::Val operator[](size_t i) const {
132         // These redundant asserts work around what we think is a codegen bug in GCC 8.x for
133         // 32-bit x86 Debug builds.
134         SkASSERT(i < fVals.size());
135         return fVals[i];
136     }
137 
asSpanSkSL::__anonf8b5168e0211::Value138     SkSpan<skvm::Val> asSpan() { return SkMakeSpan(fVals); }
139 
140 private:
141     SkSTArray<4, skvm::Val, true> fVals;
142 };
143 
144 }  // namespace
145 
146 class SkVMGenerator {
147 public:
148     SkVMGenerator(const Program& program,
149                   skvm::Builder* builder,
150                   SkVMDebugTrace* debugTrace,
151                   SkVMCallbacks* callbacks);
152 
153     void writeProgram(SkSpan<skvm::Val> uniforms,
154                       skvm::Coord device,
155                       const FunctionDefinition& function,
156                       SkSpan<skvm::Val> arguments,
157                       SkSpan<skvm::Val> outReturn);
158 
159 private:
160     /**
161      * In SkSL, a Variable represents a named, typed value (along with qualifiers, etc).
162      * Every Variable is mapped to one (or several, contiguous) indices into our vector of
163      * skvm::Val. Those skvm::Val entries hold the current actual value of that variable.
164      *
165      * NOTE: Conceptually, each Variable is just mapped to a Value. We could implement it that way,
166      * (and eliminate the indirection), but it would add overhead for each Variable,
167      * and add additional (different) bookkeeping for things like lvalue-swizzles.
168      *
169      * Any time a variable appears in an expression, that's a VariableReference, which is a kind of
170      * Expression. Evaluating that VariableReference (or any other Expression) produces a Value,
171      * which is a set of skvm::Val. (This allows an Expression to produce a vector or matrix, in
172      * addition to a scalar).
173      *
174      * For a VariableReference, producing a Value is straightforward - we get the slot of the
175      * Variable (from fVariableMap), use that to look up the current skvm::Vals holding the
176      * variable's contents, and construct a Value with those ids.
177      */
178 
179     /** Creates a Value from a collection of adjacent slots. */
180     Value getSlotValue(size_t slot, size_t nslots);
181 
182     /**
183      * Returns the slot index of this function inside the SkVMFunctionInfo array in SkVMDebugTrace.
184      * The SkVMFunctionInfo slot will be created if it doesn't already exist.
185      */
186     int getDebugFunctionInfo(const FunctionDeclaration& decl);
187 
188     /** Used by `createSlot` to add this variable to the SkVMSlotInfo array inside SkVMDebugTrace.*/
189     void addDebugSlotInfo(const std::string& varName, const Type& type, int line,
190                           int fnReturnValue);
191 
192     void addDebugSlotInfoForGroup(const std::string& varName, const Type& type, int line,
193                                   int* groupIndex, int fnReturnValue);
194 
195     /** Used by `getSlot` to create a new slot on its first access. */
196     size_t createSlot(const std::string& name, const Type& type, int line, int fnReturnValue);
197 
198     /**
199      * Returns the slot holding v's Val(s). Allocates storage if this is first time 'v' is
200      * referenced. Compound variables (e.g. vectors) will consume more than one slot, with
201      * getSlot returning the start of the contiguous chunk of slots.
202      */
203     size_t getSlot(const Variable& v);
204 
205     /**
206      * Returns the slot holding fn's return value. Allocates storage if this is first time accessing
207      * the slot.
208      */
209     size_t getSlot(const FunctionDefinition& fn);
210 
211     /**
212      * Writes a value to a slot previously created by getSlot.
213      */
214     void writeToSlot(int slot, skvm::Val value);
215 
216     /**
217      * Emits an trace_line opcode. writeStatement does this, and statements that alter control flow
218      * may need to explicitly add additional traces.
219      */
220     void emitTraceLine(int line);
221 
222     /** Emits an trace_scope opcode, which alters the SkSL variable-scope depth. */
223     void emitTraceScope(skvm::I32 executionMask, int delta);
224 
225     /** Initializes uniforms and global variables at the start of main(). */
226     void setupGlobals(SkSpan<skvm::Val> uniforms, skvm::Coord device);
227 
228     /** Emits an SkSL function. Returns the slot index of the SkSL function's return value. */
229     size_t writeFunction(const FunctionDefinition& function, SkSpan<skvm::Val> arguments);
230 
f32(skvm::Val id)231     skvm::F32 f32(skvm::Val id) { SkASSERT(id != skvm::NA); return {fBuilder, id}; }
i32(skvm::Val id)232     skvm::I32 i32(skvm::Val id) { SkASSERT(id != skvm::NA); return {fBuilder, id}; }
233 
234     // Shorthand for scalars
f32(const Value & v)235     skvm::F32 f32(const Value& v) { SkASSERT(v.slots() == 1); return f32(v[0]); }
i32(const Value & v)236     skvm::I32 i32(const Value& v) { SkASSERT(v.slots() == 1); return i32(v[0]); }
237 
238     template <typename Fn>
unary(const Value & v,Fn && fn)239     Value unary(const Value& v, Fn&& fn) {
240         Value result(v.slots());
241         for (size_t i = 0; i < v.slots(); ++i) {
242             result[i] = fn({fBuilder, v[i]});
243         }
244         return result;
245     }
246 
mask()247     skvm::I32 mask() {
248         // Mask off execution if we have encountered `break` or `continue` on this path.
249         skvm::I32 result = fConditionMask & fLoopMask;
250         if (!fFunctionStack.empty()) {
251             // As we encounter (possibly conditional) return statements, fReturned is updated to
252             // store the lanes that have already returned. For the remainder of the current
253             // function, those lanes should be disabled.
254             result = result & ~currentFunction().fReturned;
255         }
256         return result;
257     }
258 
259     size_t fieldSlotOffset(const FieldAccess& expr);
260     size_t indexSlotOffset(const IndexExpression& expr);
261 
262     Value writeExpression(const Expression& expr);
263     Value writeBinaryExpression(const BinaryExpression& b);
264     Value writeAggregationConstructor(const AnyConstructor& c);
265     Value writeChildCall(const ChildCall& c);
266     Value writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c);
267     Value writeConstructorMatrixResize(const ConstructorMatrixResize& c);
268     Value writeConstructorCast(const AnyConstructor& c);
269     Value writeConstructorSplat(const ConstructorSplat& c);
270     Value writeFunctionCall(const FunctionCall& c);
271     Value writeExternalFunctionCall(const ExternalFunctionCall& c);
272     Value writeFieldAccess(const FieldAccess& expr);
273     Value writeLiteral(const Literal& l);
274     Value writeIndexExpression(const IndexExpression& expr);
275     Value writeIntrinsicCall(const FunctionCall& c);
276     Value writePostfixExpression(const PostfixExpression& p);
277     Value writePrefixExpression(const PrefixExpression& p);
278     Value writeSwizzle(const Swizzle& swizzle);
279     Value writeTernaryExpression(const TernaryExpression& t);
280     Value writeVariableExpression(const VariableReference& expr);
281 
282     Value writeTypeConversion(const Value& src, Type::NumberKind srcKind, Type::NumberKind dstKind);
283 
284     void writeStatement(const Statement& s);
285     void writeBlock(const Block& b);
286     void writeBreakStatement();
287     void writeContinueStatement();
288     void writeForStatement(const ForStatement& f);
289     void writeIfStatement(const IfStatement& stmt);
290     void writeReturnStatement(const ReturnStatement& r);
291     void writeSwitchStatement(const SwitchStatement& s);
292     void writeVarDeclaration(const VarDeclaration& decl);
293 
294     Value writeStore(const Expression& lhs, const Value& rhs);
295     skvm::Val writeConditionalStore(skvm::Val lhs, skvm::Val rhs, skvm::I32 mask);
296 
297     Value writeMatrixInverse2x2(const Value& m);
298     Value writeMatrixInverse3x3(const Value& m);
299     Value writeMatrixInverse4x4(const Value& m);
300 
301     void recursiveBinaryCompare(const Value& lVal, const Type& lType,
302                                 const Value& rVal, const Type& rType,
303                                 size_t* slotOffset, Value* result,
304                                 const std::function <Value(skvm::F32 x, skvm::F32 y)>& float_comp,
305                                 const std::function <Value(skvm::I32 x, skvm::I32 y)>& int_comp);
306 
307     //
308     // Global state for the lifetime of the generator:
309     //
310     const Program& fProgram;
311     skvm::Builder* fBuilder;
312     SkVMDebugTrace* fDebugTrace;
313     int fTraceHookID = -1;
314     SkVMCallbacks* fCallbacks;
315 
316     struct Slot {
317         skvm::Val  val;
318         bool       writtenTo = false;
319     };
320     std::vector<Slot> fSlots;
321 
322     // [Variable, first slot in fSlots]
323     std::unordered_map<const Variable*, size_t> fVariableMap;
324     // [Function, first slot in fSlots]
325     std::unordered_map<const FunctionDefinition*, size_t> fReturnValueMap;
326 
327     // Debug trace mask (set to true when fTraceCoord matches device coordinates)
328     skvm::I32 fTraceMask;
329 
330     // Conditional execution mask (managed by ScopedCondition, and tied to control-flow scopes)
331     skvm::I32 fConditionMask;
332 
333     // Similar: loop execution masks. Each loop starts with all lanes active (fLoopMask).
334     // 'break' disables a lane in fLoopMask until the loop finishes
335     // 'continue' disables a lane in fLoopMask, and sets fContinueMask to be re-enabled on the next
336     //   iteration
337     skvm::I32 fLoopMask;
338     skvm::I32 fContinueMask;
339 
340     //
341     // State that's local to the generation of a single function:
342     //
343     struct Function {
344         size_t     fReturnSlot;
345         skvm::I32  fReturned;
346     };
347     std::vector<Function> fFunctionStack;
currentFunction()348     Function& currentFunction() { return fFunctionStack.back(); }
349 
350     class ScopedCondition {
351     public:
ScopedCondition(SkVMGenerator * generator,skvm::I32 mask)352         ScopedCondition(SkVMGenerator* generator, skvm::I32 mask)
353                 : fGenerator(generator), fOldConditionMask(fGenerator->fConditionMask) {
354             fGenerator->fConditionMask &= mask;
355         }
356 
~ScopedCondition()357         ~ScopedCondition() { fGenerator->fConditionMask = fOldConditionMask; }
358 
359     private:
360         SkVMGenerator* fGenerator;
361         skvm::I32 fOldConditionMask;
362     };
363 };
364 
base_number_kind(const Type & type)365 static Type::NumberKind base_number_kind(const Type& type) {
366     if (type.typeKind() == Type::TypeKind::kMatrix || type.typeKind() == Type::TypeKind::kVector) {
367         return base_number_kind(type.componentType());
368     }
369     return type.numberKind();
370 }
371 
is_uniform(const SkSL::Variable & var)372 static inline bool is_uniform(const SkSL::Variable& var) {
373     return var.modifiers().fFlags & Modifiers::kUniform_Flag;
374 }
375 
SkVMGenerator(const Program & program,skvm::Builder * builder,SkVMDebugTrace * debugTrace,SkVMCallbacks * callbacks)376 SkVMGenerator::SkVMGenerator(const Program& program,
377                              skvm::Builder* builder,
378                              SkVMDebugTrace* debugTrace,
379                              SkVMCallbacks* callbacks)
380         : fProgram(program)
381         , fBuilder(builder)
382         , fDebugTrace(debugTrace)
383         , fCallbacks(callbacks) {}
384 
writeProgram(SkSpan<skvm::Val> uniforms,skvm::Coord device,const FunctionDefinition & function,SkSpan<skvm::Val> arguments,SkSpan<skvm::Val> outReturn)385 void SkVMGenerator::writeProgram(SkSpan<skvm::Val> uniforms,
386                                  skvm::Coord device,
387                                  const FunctionDefinition& function,
388                                  SkSpan<skvm::Val> arguments,
389                                  SkSpan<skvm::Val> outReturn) {
390     fConditionMask = fLoopMask = fBuilder->splat(0xffff'ffff);
391 
392     this->setupGlobals(uniforms, device);
393     size_t returnSlot = this->writeFunction(function, arguments);
394 
395     // Copy the value from the return slot into outReturn.
396     SkASSERT(function.declaration().returnType().slotCount() == outReturn.size());
397     for (size_t i = 0; i < outReturn.size(); ++i) {
398         outReturn[i] = fSlots[returnSlot + i].val;
399     }
400 }
401 
setupGlobals(SkSpan<skvm::Val> uniforms,skvm::Coord device)402 void SkVMGenerator::setupGlobals(SkSpan<skvm::Val> uniforms, skvm::Coord device) {
403     if (fDebugTrace) {
404         // Copy the program source into the debug info so that it will be written in the trace file.
405         fDebugTrace->setSource(*fProgram.fSource);
406 
407         // Create a trace hook and attach it to the builder.
408         fDebugTrace->fTraceHook = SkSLTracer::Make(fDebugTrace);
409         fTraceHookID = fBuilder->attachTraceHook(fDebugTrace->fTraceHook.get());
410 
411         // The SkVM blitter generates centered pixel coordinates. (0.5, 1.5, 2.5, 3.5, etc.)
412         // Add 0.5 to the requested trace coordinate to match this.
413         skvm::Coord traceCoord = {to_F32(fBuilder->splat(fDebugTrace->fTraceCoord.fX)) + 0.5f,
414                                   to_F32(fBuilder->splat(fDebugTrace->fTraceCoord.fY)) + 0.5f};
415 
416         // If we are debugging, we need to create a trace mask. This will be true when the current
417         // device coordinates match the requested trace coordinates. We calculate each mask
418         // individually to guarantee consistent order-of-evaluation.
419         skvm::I32 xMask = (device.x == traceCoord.x),
420                   yMask = (device.y == traceCoord.y);
421         fTraceMask = xMask & yMask;
422     }
423 
424     // Add storage for each global variable (including uniforms) to fSlots, and entries in
425     // fVariableMap to remember where every variable is stored.
426     const skvm::Val* uniformIter = uniforms.begin();
427     size_t fpCount = 0;
428     for (const ProgramElement* e : fProgram.elements()) {
429         if (e->is<GlobalVarDeclaration>()) {
430             const GlobalVarDeclaration& gvd = e->as<GlobalVarDeclaration>();
431             const VarDeclaration& decl = gvd.declaration()->as<VarDeclaration>();
432             const Variable& var = decl.var();
433             SkASSERT(fVariableMap.find(&var) == fVariableMap.end());
434 
435             // For most variables, fVariableMap stores an index into fSlots, but for children,
436             // fVariableMap stores the index to pass to fSample(Shader|ColorFilter|Blender)
437             if (var.type().isEffectChild()) {
438                 fVariableMap[&var] = fpCount++;
439                 continue;
440             }
441 
442             // Opaque types include child processors and GL objects (samplers, textures, etc).
443             // Of those, only child processors are legal variables.
444             SkASSERT(!var.type().isVoid());
445             SkASSERT(!var.type().isOpaque());
446 
447             // getSlot() allocates space for the variable's value in fSlots, initializes it to zero,
448             // and populates fVariableMap.
449             size_t slot   = this->getSlot(var),
450                    nslots = var.type().slotCount();
451 
452             // builtin variables are system-defined, with special semantics. The only builtin
453             // variable exposed to runtime effects is sk_FragCoord.
454             if (int builtin = var.modifiers().fLayout.fBuiltin; builtin >= 0) {
455                 switch (builtin) {
456                     case SK_FRAGCOORD_BUILTIN:
457                         SkASSERT(nslots == 4);
458                         this->writeToSlot(slot + 0, device.x.id);
459                         this->writeToSlot(slot + 1, device.y.id);
460                         this->writeToSlot(slot + 2, fBuilder->splat(0.0f).id);
461                         this->writeToSlot(slot + 3, fBuilder->splat(1.0f).id);
462                         break;
463                     default:
464                         SkDEBUGFAILF("Unsupported builtin %d", builtin);
465                 }
466                 continue;
467             }
468 
469             // For uniforms, copy the supplied IDs over
470             if (is_uniform(var)) {
471                 SkASSERT(uniformIter + nslots <= uniforms.end());
472                 for (size_t i = 0; i < nslots; ++i) {
473                     this->writeToSlot(slot + i, uniformIter[i]);
474                 }
475                 uniformIter += nslots;
476                 continue;
477             }
478 
479             // For other globals, populate with the initializer expression (if there is one)
480             if (decl.value()) {
481                 Value val = this->writeExpression(*decl.value());
482                 for (size_t i = 0; i < nslots; ++i) {
483                     this->writeToSlot(slot + i, val[i]);
484                 }
485             }
486         }
487     }
488     SkASSERT(uniformIter == uniforms.end());
489 }
490 
getSlotValue(size_t slot,size_t nslots)491 Value SkVMGenerator::getSlotValue(size_t slot, size_t nslots) {
492     Value val(nslots);
493     for (size_t i = 0; i < nslots; ++i) {
494         val[i] = fSlots[slot + i].val;
495     }
496     return val;
497 }
498 
getDebugFunctionInfo(const FunctionDeclaration & decl)499 int SkVMGenerator::getDebugFunctionInfo(const FunctionDeclaration& decl) {
500     SkASSERT(fDebugTrace);
501 
502     std::string name = decl.description();
503 
504     // Look for a matching SkVMFunctionInfo slot.
505     for (size_t index = 0; index < fDebugTrace->fFuncInfo.size(); ++index) {
506         if (fDebugTrace->fFuncInfo[index].name == name) {
507             return index;
508         }
509     }
510 
511     // We've never called this function before; create a new slot to hold its information.
512     int slot = (int)fDebugTrace->fFuncInfo.size();
513     fDebugTrace->fFuncInfo.push_back(SkVMFunctionInfo{std::move(name)});
514     return slot;
515 }
516 
writeFunction(const FunctionDefinition & function,SkSpan<skvm::Val> arguments)517 size_t SkVMGenerator::writeFunction(const FunctionDefinition& function,
518                                     SkSpan<skvm::Val> arguments) {
519     const FunctionDeclaration& decl = function.declaration();
520 
521     int funcIndex = -1;
522     if (fDebugTrace) {
523         funcIndex = this->getDebugFunctionInfo(decl);
524         fBuilder->trace_enter(fTraceHookID, this->mask(), fTraceMask, funcIndex);
525     }
526 
527     size_t returnSlot = this->getSlot(function);
528     fFunctionStack.push_back({/*fReturnSlot=*/returnSlot, /*fReturned=*/fBuilder->splat(0)});
529 
530     // For all parameters, copy incoming argument IDs to our vector of (all) variable IDs
531     size_t argIdx = 0;
532     for (const Variable* p : decl.parameters()) {
533         size_t paramSlot = this->getSlot(*p),
534                nslots    = p->type().slotCount();
535 
536         for (size_t i = 0; i < nslots; ++i) {
537             fSlots[paramSlot + i].writtenTo = false;
538             this->writeToSlot(paramSlot + i, arguments[argIdx + i]);
539         }
540         argIdx += nslots;
541     }
542     SkASSERT(argIdx == arguments.size());
543 
544     this->writeStatement(*function.body());
545 
546     // Copy 'out' and 'inout' parameters back to their caller-supplied argument storage
547     argIdx = 0;
548     for (const Variable* p : decl.parameters()) {
549         size_t nslots = p->type().slotCount();
550 
551         if (p->modifiers().fFlags & Modifiers::kOut_Flag) {
552             size_t paramSlot = this->getSlot(*p);
553             for (size_t i = 0; i < nslots; ++i) {
554                 arguments[argIdx + i] = fSlots[paramSlot + i].val;
555             }
556         }
557         argIdx += nslots;
558     }
559     SkASSERT(argIdx == arguments.size());
560 
561     fFunctionStack.pop_back();
562 
563     if (fDebugTrace) {
564         fBuilder->trace_exit(fTraceHookID, this->mask(), fTraceMask, funcIndex);
565     }
566 
567     return returnSlot;
568 }
569 
writeToSlot(int slot,skvm::Val value)570 void SkVMGenerator::writeToSlot(int slot, skvm::Val value) {
571     if (fDebugTrace && (!fSlots[slot].writtenTo || fSlots[slot].val != value)) {
572         if (fProgram.fConfig->fSettings.fAllowTraceVarInSkVMDebugTrace) {
573             fBuilder->trace_var(fTraceHookID, this->mask(), fTraceMask, slot, i32(value));
574         }
575         fSlots[slot].writtenTo = true;
576     }
577 
578     fSlots[slot].val = value;
579 }
580 
addDebugSlotInfoForGroup(const std::string & varName,const Type & type,int line,int * groupIndex,int fnReturnValue)581 void SkVMGenerator::addDebugSlotInfoForGroup(const std::string& varName, const Type& type, int line,
582                                              int* groupIndex, int fnReturnValue) {
583     SkASSERT(fDebugTrace);
584     switch (type.typeKind()) {
585         case Type::TypeKind::kArray: {
586             int nslots = type.columns();
587             const Type& elemType = type.componentType();
588             for (int slot = 0; slot < nslots; ++slot) {
589                 this->addDebugSlotInfoForGroup(varName + "[" + std::to_string(slot) + "]", elemType,
590                                                line, groupIndex, fnReturnValue);
591             }
592             break;
593         }
594         case Type::TypeKind::kStruct: {
595             for (const Type::Field& field : type.fields()) {
596                 this->addDebugSlotInfoForGroup(varName + "." + std::string(field.fName),
597                                                *field.fType, line, groupIndex, fnReturnValue);
598             }
599             break;
600         }
601         default:
602             SkASSERTF(0, "unsupported slot type %d", (int)type.typeKind());
603             [[fallthrough]];
604 
605         case Type::TypeKind::kScalar:
606         case Type::TypeKind::kVector:
607         case Type::TypeKind::kMatrix: {
608             Type::NumberKind numberKind = type.componentType().numberKind();
609             int nslots = type.slotCount();
610 
611             for (int slot = 0; slot < nslots; ++slot) {
612                 SkVMSlotInfo slotInfo;
613                 slotInfo.name = varName;
614                 slotInfo.columns = type.columns();
615                 slotInfo.rows = type.rows();
616                 slotInfo.componentIndex = slot;
617                 slotInfo.groupIndex = (*groupIndex)++;
618                 slotInfo.numberKind = numberKind;
619                 slotInfo.line = line;
620                 slotInfo.fnReturnValue = fnReturnValue;
621                 fDebugTrace->fSlotInfo.push_back(std::move(slotInfo));
622             }
623             break;
624         }
625     }
626 }
627 
addDebugSlotInfo(const std::string & varName,const Type & type,int line,int fnReturnValue)628 void SkVMGenerator::addDebugSlotInfo(const std::string& varName, const Type& type, int line,
629                                      int fnReturnValue) {
630     int groupIndex = 0;
631     this->addDebugSlotInfoForGroup(varName, type, line, &groupIndex, fnReturnValue);
632     SkASSERT((size_t)groupIndex == type.slotCount());
633 }
634 
createSlot(const std::string & name,const Type & type,int line,int fnReturnValue)635 size_t SkVMGenerator::createSlot(const std::string& name,
636                                  const Type& type,
637                                  int line,
638                                  int fnReturnValue) {
639     size_t slot   = fSlots.size(),
640            nslots = type.slotCount();
641 
642     if (nslots > 0) {
643         if (fDebugTrace) {
644             // Our debug slot-info table should have the same length as the actual slot table.
645             SkASSERT(fDebugTrace->fSlotInfo.size() == slot);
646 
647             // Append slot names and types to our debug slot-info table.
648             fDebugTrace->fSlotInfo.reserve(slot + nslots);
649             this->addDebugSlotInfo(name, type, line, fnReturnValue);
650 
651             // Confirm that we added the expected number of slots.
652             SkASSERT(fDebugTrace->fSlotInfo.size() == (slot + nslots));
653         }
654 
655         // Create brand new slots initialized to zero.
656         skvm::Val initialValue = fBuilder->splat(0.0f).id;
657         fSlots.insert(fSlots.end(), nslots, Slot{initialValue});
658     }
659     return slot;
660 }
661 
getSlot(const Variable & v)662 size_t SkVMGenerator::getSlot(const Variable& v) {
663     auto entry = fVariableMap.find(&v);
664     if (entry != fVariableMap.end()) {
665         return entry->second;
666     }
667 
668     size_t slot = this->createSlot(std::string(v.name()), v.type(), v.fLine, /*fnReturnValue=*/-1);
669     fVariableMap[&v] = slot;
670     return slot;
671 }
672 
getSlot(const FunctionDefinition & fn)673 size_t SkVMGenerator::getSlot(const FunctionDefinition& fn) {
674     auto entry = fReturnValueMap.find(&fn);
675     if (entry != fReturnValueMap.end()) {
676         return entry->second;
677     }
678 
679     const FunctionDeclaration& decl = fn.declaration();
680     int fnReturnValue = fDebugTrace ? this->getDebugFunctionInfo(decl) : -1;
681 
682     size_t slot = this->createSlot("[" + std::string(decl.name()) + "].result",
683                                    decl.returnType(),
684                                    fn.fLine,
685                                    fnReturnValue);
686     fReturnValueMap[&fn] = slot;
687     return slot;
688 }
689 
recursiveBinaryCompare(const Value & lVal,const Type & lType,const Value & rVal,const Type & rType,size_t * slotOffset,Value * result,const std::function<Value (skvm::F32 x,skvm::F32 y)> & float_comp,const std::function<Value (skvm::I32 x,skvm::I32 y)> & int_comp)690 void SkVMGenerator::recursiveBinaryCompare(
691         const Value& lVal,
692         const Type& lType,
693         const Value& rVal,
694         const Type& rType,
695         size_t* slotOffset,
696         Value* result,
697         const std::function<Value(skvm::F32 x, skvm::F32 y)>& float_comp,
698         const std::function<Value(skvm::I32 x, skvm::I32 y)>& int_comp) {
699     switch (lType.typeKind()) {
700         case Type::TypeKind::kStruct:
701             SkASSERT(rType.typeKind() == Type::TypeKind::kStruct);
702             // Go through all the fields
703             for (size_t f = 0; f < lType.fields().size(); ++f) {
704                 const Type::Field& lField = lType.fields()[f];
705                 const Type::Field& rField = rType.fields()[f];
706                 this->recursiveBinaryCompare(lVal,
707                                              *lField.fType,
708                                              rVal,
709                                              *rField.fType,
710                                              slotOffset,
711                                              result,
712                                              float_comp,
713                                              int_comp);
714             }
715             break;
716 
717         case Type::TypeKind::kArray:
718         case Type::TypeKind::kVector:
719         case Type::TypeKind::kMatrix:
720             SkASSERT(lType.typeKind() == rType.typeKind());
721             // Go through all the elements
722             for (int c = 0; c < lType.columns(); ++c) {
723                 this->recursiveBinaryCompare(lVal,
724                                              lType.componentType(),
725                                              rVal,
726                                              rType.componentType(),
727                                              slotOffset,
728                                              result,
729                                              float_comp,
730                                              int_comp);
731             }
732             break;
733         default:
734             SkASSERT(lType.typeKind() == rType.typeKind() &&
735                      lType.slotCount() == rType.slotCount());
736             Type::NumberKind nk = base_number_kind(lType);
737             auto L = lVal[*slotOffset];
738             auto R = rVal[*slotOffset];
739             (*result)[*slotOffset] =
740                     i32(nk == Type::NumberKind::kFloat
741                           ? float_comp(f32(L), f32(R))
742                           : int_comp(i32(L), i32(R))).id;
743             *slotOffset += lType.slotCount();
744             break;
745     }
746 }
747 
writeBinaryExpression(const BinaryExpression & b)748 Value SkVMGenerator::writeBinaryExpression(const BinaryExpression& b) {
749     const Expression& left = *b.left();
750     const Expression& right = *b.right();
751     Operator op = b.getOperator();
752     if (op.kind() == Token::Kind::TK_EQ) {
753         return this->writeStore(left, this->writeExpression(right));
754     }
755 
756     const Type& lType = left.type();
757     const Type& rType = right.type();
758     bool lVecOrMtx = (lType.isVector() || lType.isMatrix());
759     bool rVecOrMtx = (rType.isVector() || rType.isMatrix());
760     bool isAssignment = op.isAssignment();
761     if (isAssignment) {
762         op = op.removeAssignment();
763     }
764     Type::NumberKind nk = base_number_kind(lType);
765 
766     // A few ops require special treatment:
767     switch (op.kind()) {
768         case Token::Kind::TK_LOGICALAND: {
769             SkASSERT(!isAssignment);
770             SkASSERT(nk == Type::NumberKind::kBoolean);
771             skvm::I32 lVal = i32(this->writeExpression(left));
772             ScopedCondition shortCircuit(this, lVal);
773             skvm::I32 rVal = i32(this->writeExpression(right));
774             return lVal & rVal;
775         }
776         case Token::Kind::TK_LOGICALOR: {
777             SkASSERT(!isAssignment);
778             SkASSERT(nk == Type::NumberKind::kBoolean);
779             skvm::I32 lVal = i32(this->writeExpression(left));
780             ScopedCondition shortCircuit(this, ~lVal);
781             skvm::I32 rVal = i32(this->writeExpression(right));
782             return lVal | rVal;
783         }
784         case Token::Kind::TK_COMMA:
785             // We write the left side of the expression to preserve its side effects, even though we
786             // immediately discard the result.
787             this->writeExpression(left);
788             return this->writeExpression(right);
789         default:
790             break;
791     }
792 
793     // All of the other ops always evaluate both sides of the expression
794     Value lVal = this->writeExpression(left),
795           rVal = this->writeExpression(right);
796 
797     // Special case for M*V, V*M, M*M (but not V*V!)
798     if (op.kind() == Token::Kind::TK_STAR
799         && lVecOrMtx && rVecOrMtx && !(lType.isVector() && rType.isVector())) {
800         int rCols = rType.columns(),
801             rRows = rType.rows(),
802             lCols = lType.columns(),
803             lRows = lType.rows();
804         // M*V treats the vector as a column
805         if (rType.isVector()) {
806             std::swap(rCols, rRows);
807         }
808         SkASSERT(lCols == rRows);
809         SkASSERT(b.type().slotCount() == static_cast<size_t>(lRows * rCols));
810         Value result(lRows * rCols);
811         size_t resultIdx = 0;
812         const skvm::F32 zero = fBuilder->splat(0.0f);
813         for (int c = 0; c < rCols; ++c)
814         for (int r = 0; r < lRows; ++r) {
815             skvm::F32 sum = zero;
816             for (int j = 0; j < lCols; ++j) {
817                 sum += f32(lVal[j*lRows + r]) * f32(rVal[c*rRows + j]);
818             }
819             result[resultIdx++] = sum;
820         }
821         SkASSERT(resultIdx == result.slots());
822         return isAssignment ? this->writeStore(left, result) : result;
823     }
824 
825     size_t nslots = std::max(lVal.slots(), rVal.slots());
826 
827     auto binary = [&](const std::function <Value(skvm::F32 x, skvm::F32 y)>& f_fn,
828                       const std::function <Value(skvm::I32 x, skvm::I32 y)>& i_fn,
829                       bool foldResults = false) -> Value {
830 
831         Value result(nslots);
832         if (op.isEquality() && (lType.typeKind() == Type::TypeKind::kStruct ||
833                                 lType.typeKind() == Type::TypeKind::kArray)) {
834             // Shifting over lVal and rVal
835             size_t slotOffset = 0;
836             this->recursiveBinaryCompare(
837                     lVal, lType, rVal, rType, &slotOffset, &result, f_fn, i_fn);
838             SkASSERT(slotOffset == nslots);
839         } else {
840             for (size_t slot = 0; slot < nslots; ++slot) {
841                 // If one side is scalar, replicate it to all channels
842                 skvm::Val L = lVal.slots() == 1 ? lVal[0] : lVal[slot],
843                           R = rVal.slots() == 1 ? rVal[0] : rVal[slot];
844 
845                 if (nk == Type::NumberKind::kFloat) {
846                     result[slot] = i32(f_fn(f32(L), f32(R)));
847                 } else {
848                     result[slot] = i32(i_fn(i32(L), i32(R)));
849                 }
850             }
851         }
852 
853         if (foldResults) {
854             // Just to be more explicit here we ask for a parameter and not detect it ourselves
855             SkASSERT(op.isEquality());
856             skvm::I32 folded = i32(result[0]);
857             for (size_t i = 1; i < nslots; ++i) {
858                 if (op.kind() == Token::Kind::TK_NEQ) {
859                     folded |= i32(result[i]);
860                 } else {
861                     folded &= i32(result[i]);
862                 }
863             }
864             return folded;
865         }
866 
867         return isAssignment ? this->writeStore(left, result) : result;
868     };
869 
870     auto unsupported_f = [&](skvm::F32, skvm::F32) {
871         SkDEBUGFAIL("Unsupported operator");
872         return skvm::F32{};
873     };
874 
875     switch (op.kind()) {
876         case Token::Kind::TK_EQEQ:
877             SkASSERT(!isAssignment);
878             return binary([](skvm::F32 x, skvm::F32 y) { return x == y; },
879                           [](skvm::I32 x, skvm::I32 y) { return x == y; }, /*foldResults=*/ true);
880         case Token::Kind::TK_NEQ:
881             SkASSERT(!isAssignment);
882             return binary([](skvm::F32 x, skvm::F32 y) { return x != y; },
883                           [](skvm::I32 x, skvm::I32 y) { return x != y; }, /*foldResults=*/ true);
884         case Token::Kind::TK_GT:
885             return binary([](skvm::F32 x, skvm::F32 y) { return x > y; },
886                           [](skvm::I32 x, skvm::I32 y) { return x > y; });
887         case Token::Kind::TK_GTEQ:
888             return binary([](skvm::F32 x, skvm::F32 y) { return x >= y; },
889                           [](skvm::I32 x, skvm::I32 y) { return x >= y; });
890         case Token::Kind::TK_LT:
891             return binary([](skvm::F32 x, skvm::F32 y) { return x < y; },
892                           [](skvm::I32 x, skvm::I32 y) { return x < y; });
893         case Token::Kind::TK_LTEQ:
894             return binary([](skvm::F32 x, skvm::F32 y) { return x <= y; },
895                           [](skvm::I32 x, skvm::I32 y) { return x <= y; });
896 
897         case Token::Kind::TK_PLUS:
898             return binary([](skvm::F32 x, skvm::F32 y) { return x + y; },
899                           [](skvm::I32 x, skvm::I32 y) { return x + y; });
900         case Token::Kind::TK_MINUS:
901             return binary([](skvm::F32 x, skvm::F32 y) { return x - y; },
902                           [](skvm::I32 x, skvm::I32 y) { return x - y; });
903         case Token::Kind::TK_STAR:
904             return binary([](skvm::F32 x, skvm::F32 y) { return x ** y; },
905                           [](skvm::I32 x, skvm::I32 y) { return x * y; });
906         case Token::Kind::TK_SLASH:
907             // Minimum spec (GLSL ES 1.0) has very loose requirements for integer operations.
908             // (Low-end GPUs may not have integer ALUs). Given that, we are allowed to do floating
909             // point division plus rounding. Section 10.28 of the spec even clarifies that the
910             // rounding mode is undefined (but round-towards-zero is the obvious/common choice).
911             return binary([](skvm::F32 x, skvm::F32 y) { return x / y; },
912                           [](skvm::I32 x, skvm::I32 y) {
913                               return skvm::trunc(skvm::to_F32(x) / skvm::to_F32(y));
914                           });
915 
916         case Token::Kind::TK_BITWISEXOR:
917         case Token::Kind::TK_LOGICALXOR:
918             return binary(unsupported_f, [](skvm::I32 x, skvm::I32 y) { return x ^ y; });
919         case Token::Kind::TK_BITWISEAND:
920             return binary(unsupported_f, [](skvm::I32 x, skvm::I32 y) { return x & y; });
921         case Token::Kind::TK_BITWISEOR:
922             return binary(unsupported_f, [](skvm::I32 x, skvm::I32 y) { return x | y; });
923 
924         // These three operators are all 'reserved' (illegal) in our minimum spec, but will require
925         // implementation in the future.
926         case Token::Kind::TK_PERCENT:
927         case Token::Kind::TK_SHL:
928         case Token::Kind::TK_SHR:
929         default:
930             SkDEBUGFAIL("Unsupported operator");
931             return {};
932     }
933 }
934 
writeAggregationConstructor(const AnyConstructor & c)935 Value SkVMGenerator::writeAggregationConstructor(const AnyConstructor& c) {
936     Value result(c.type().slotCount());
937     size_t resultIdx = 0;
938     for (const auto &arg : c.argumentSpan()) {
939         Value tmp = this->writeExpression(*arg);
940         for (size_t tmpSlot = 0; tmpSlot < tmp.slots(); ++tmpSlot) {
941             result[resultIdx++] = tmp[tmpSlot];
942         }
943     }
944     return result;
945 }
946 
writeTypeConversion(const Value & src,Type::NumberKind srcKind,Type::NumberKind dstKind)947 Value SkVMGenerator::writeTypeConversion(const Value& src,
948                                          Type::NumberKind srcKind,
949                                          Type::NumberKind dstKind) {
950     // Conversion among "similar" types (floatN <-> halfN), (shortN <-> intN), etc. is a no-op.
951     if (srcKind == dstKind) {
952         return src;
953     }
954 
955     // TODO: Handle signed vs. unsigned. GLSL ES 1.0 only has 'int', so no problem yet.
956     Value dst(src.slots());
957     switch (dstKind) {
958         case Type::NumberKind::kFloat:
959             if (srcKind == Type::NumberKind::kSigned) {
960                 // int -> float
961                 for (size_t i = 0; i < src.slots(); ++i) {
962                     dst[i] = skvm::to_F32(i32(src[i]));
963                 }
964                 return dst;
965             }
966             if (srcKind == Type::NumberKind::kBoolean) {
967                 // bool -> float
968                 for (size_t i = 0; i < src.slots(); ++i) {
969                     dst[i] = skvm::select(i32(src[i]), 1.0f, 0.0f);
970                 }
971                 return dst;
972             }
973             break;
974 
975         case Type::NumberKind::kSigned:
976             if (srcKind == Type::NumberKind::kFloat) {
977                 // float -> int
978                 for (size_t i = 0; i < src.slots(); ++i) {
979                     dst[i] = skvm::trunc(f32(src[i]));
980                 }
981                 return dst;
982             }
983             if (srcKind == Type::NumberKind::kBoolean) {
984                 // bool -> int
985                 for (size_t i = 0; i < src.slots(); ++i) {
986                     dst[i] = skvm::select(i32(src[i]), 1, 0);
987                 }
988                 return dst;
989             }
990             break;
991 
992         case Type::NumberKind::kBoolean:
993             if (srcKind == Type::NumberKind::kSigned) {
994                 // int -> bool
995                 for (size_t i = 0; i < src.slots(); ++i) {
996                     dst[i] = i32(src[i]) != 0;
997                 }
998                 return dst;
999             }
1000             if (srcKind == Type::NumberKind::kFloat) {
1001                 // float -> bool
1002                 for (size_t i = 0; i < src.slots(); ++i) {
1003                     dst[i] = f32(src[i]) != 0.0;
1004                 }
1005                 return dst;
1006             }
1007             break;
1008 
1009         default:
1010             break;
1011     }
1012     SkDEBUGFAILF("Unsupported type conversion: %d -> %d", (int)srcKind, (int)dstKind);
1013     return {};
1014 }
1015 
writeConstructorCast(const AnyConstructor & c)1016 Value SkVMGenerator::writeConstructorCast(const AnyConstructor& c) {
1017     auto arguments = c.argumentSpan();
1018     SkASSERT(arguments.size() == 1);
1019     const Expression& argument = *arguments.front();
1020 
1021     const Type& srcType = argument.type();
1022     const Type& dstType = c.type();
1023     Type::NumberKind srcKind = base_number_kind(srcType);
1024     Type::NumberKind dstKind = base_number_kind(dstType);
1025     Value src = this->writeExpression(argument);
1026     return this->writeTypeConversion(src, srcKind, dstKind);
1027 }
1028 
writeConstructorSplat(const ConstructorSplat & c)1029 Value SkVMGenerator::writeConstructorSplat(const ConstructorSplat& c) {
1030     SkASSERT(c.type().isVector());
1031     SkASSERT(c.argument()->type().isScalar());
1032     int columns = c.type().columns();
1033 
1034     // Splat the argument across all components of a vector.
1035     Value src = this->writeExpression(*c.argument());
1036     Value dst(columns);
1037     for (int i = 0; i < columns; ++i) {
1038         dst[i] = src[0];
1039     }
1040     return dst;
1041 }
1042 
writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix & ctor)1043 Value SkVMGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& ctor) {
1044     const Type& dstType = ctor.type();
1045     SkASSERT(dstType.isMatrix());
1046     SkASSERT(ctor.argument()->type().matches(dstType.componentType()));
1047 
1048     Value src = this->writeExpression(*ctor.argument());
1049     Value dst(dstType.rows() * dstType.columns());
1050     size_t dstIndex = 0;
1051 
1052     // Matrix-from-scalar builds a diagonal scale matrix
1053     const skvm::F32 zero = fBuilder->splat(0.0f);
1054     for (int c = 0; c < dstType.columns(); ++c) {
1055         for (int r = 0; r < dstType.rows(); ++r) {
1056             dst[dstIndex++] = (c == r ? f32(src) : zero);
1057         }
1058     }
1059 
1060     SkASSERT(dstIndex == dst.slots());
1061     return dst;
1062 }
1063 
writeConstructorMatrixResize(const ConstructorMatrixResize & ctor)1064 Value SkVMGenerator::writeConstructorMatrixResize(const ConstructorMatrixResize& ctor) {
1065     const Type& srcType = ctor.argument()->type();
1066     const Type& dstType = ctor.type();
1067     Value src = this->writeExpression(*ctor.argument());
1068     Value dst(dstType.rows() * dstType.columns());
1069 
1070     // Matrix-from-matrix uses src where it overlaps, and fills in missing fields with identity.
1071     size_t dstIndex = 0;
1072     for (int c = 0; c < dstType.columns(); ++c) {
1073         for (int r = 0; r < dstType.rows(); ++r) {
1074             if (c < srcType.columns() && r < srcType.rows()) {
1075                 dst[dstIndex++] = src[c * srcType.rows() + r];
1076             } else {
1077                 dst[dstIndex++] = fBuilder->splat(c == r ? 1.0f : 0.0f);
1078             }
1079         }
1080     }
1081 
1082     SkASSERT(dstIndex == dst.slots());
1083     return dst;
1084 }
1085 
fieldSlotOffset(const FieldAccess & expr)1086 size_t SkVMGenerator::fieldSlotOffset(const FieldAccess& expr) {
1087     size_t offset = 0;
1088     for (int i = 0; i < expr.fieldIndex(); ++i) {
1089         offset += (*expr.base()->type().fields()[i].fType).slotCount();
1090     }
1091     return offset;
1092 }
1093 
writeFieldAccess(const FieldAccess & expr)1094 Value SkVMGenerator::writeFieldAccess(const FieldAccess& expr) {
1095     Value base = this->writeExpression(*expr.base());
1096     Value field(expr.type().slotCount());
1097     size_t offset = this->fieldSlotOffset(expr);
1098     for (size_t i = 0; i < field.slots(); ++i) {
1099         field[i] = base[offset + i];
1100     }
1101     return field;
1102 }
1103 
indexSlotOffset(const IndexExpression & expr)1104 size_t SkVMGenerator::indexSlotOffset(const IndexExpression& expr) {
1105     Value index = this->writeExpression(*expr.index());
1106     int indexValue = -1;
1107     SkAssertResult(fBuilder->allImm(index[0], &indexValue));
1108 
1109     // When indexing by a literal, the front-end guarantees that we don't go out of bounds.
1110     // But when indexing by a loop variable, it's possible to generate out-of-bounds access.
1111     // The GLSL spec leaves that behavior undefined - we'll just clamp everything here.
1112     indexValue = SkTPin(indexValue, 0, expr.base()->type().columns() - 1);
1113 
1114     size_t stride = expr.type().slotCount();
1115     return indexValue * stride;
1116 }
1117 
writeIndexExpression(const IndexExpression & expr)1118 Value SkVMGenerator::writeIndexExpression(const IndexExpression& expr) {
1119     Value base = this->writeExpression(*expr.base());
1120     Value element(expr.type().slotCount());
1121     size_t offset = this->indexSlotOffset(expr);
1122     for (size_t i = 0; i < element.slots(); ++i) {
1123         element[i] = base[offset + i];
1124     }
1125     return element;
1126 }
1127 
writeVariableExpression(const VariableReference & expr)1128 Value SkVMGenerator::writeVariableExpression(const VariableReference& expr) {
1129     size_t slot = this->getSlot(*expr.variable());
1130     return this->getSlotValue(slot, expr.type().slotCount());
1131 }
1132 
writeMatrixInverse2x2(const Value & m)1133 Value SkVMGenerator::writeMatrixInverse2x2(const Value& m) {
1134     SkASSERT(m.slots() == 4);
1135     skvm::F32 a = f32(m[0]),
1136               b = f32(m[1]),
1137               c = f32(m[2]),
1138               d = f32(m[3]);
1139     skvm::F32 idet = 1.0f / (a*d - b*c);
1140 
1141     Value result(m.slots());
1142     result[0] = ( d ** idet);
1143     result[1] = (-b ** idet);
1144     result[2] = (-c ** idet);
1145     result[3] = ( a ** idet);
1146     return result;
1147 }
1148 
writeMatrixInverse3x3(const Value & m)1149 Value SkVMGenerator::writeMatrixInverse3x3(const Value& m) {
1150     SkASSERT(m.slots() == 9);
1151     skvm::F32 a11 = f32(m[0]), a12 = f32(m[3]), a13 = f32(m[6]),
1152               a21 = f32(m[1]), a22 = f32(m[4]), a23 = f32(m[7]),
1153               a31 = f32(m[2]), a32 = f32(m[5]), a33 = f32(m[8]);
1154     skvm::F32 idet = 1.0f / (a11*a22*a33 + a12*a23*a31 + a13*a21*a32 -
1155                              a11*a23*a32 - a12*a21*a33 - a13*a22*a31);
1156 
1157     Value result(m.slots());
1158     result[0] = ((a22**a33 - a23**a32) ** idet);
1159     result[1] = ((a23**a31 - a21**a33) ** idet);
1160     result[2] = ((a21**a32 - a22**a31) ** idet);
1161     result[3] = ((a13**a32 - a12**a33) ** idet);
1162     result[4] = ((a11**a33 - a13**a31) ** idet);
1163     result[5] = ((a12**a31 - a11**a32) ** idet);
1164     result[6] = ((a12**a23 - a13**a22) ** idet);
1165     result[7] = ((a13**a21 - a11**a23) ** idet);
1166     result[8] = ((a11**a22 - a12**a21) ** idet);
1167     return result;
1168 }
1169 
writeMatrixInverse4x4(const Value & m)1170 Value SkVMGenerator::writeMatrixInverse4x4(const Value& m) {
1171     SkASSERT(m.slots() == 16);
1172     skvm::F32 a00 = f32(m[0]), a10 = f32(m[4]), a20 = f32(m[ 8]), a30 = f32(m[12]),
1173               a01 = f32(m[1]), a11 = f32(m[5]), a21 = f32(m[ 9]), a31 = f32(m[13]),
1174               a02 = f32(m[2]), a12 = f32(m[6]), a22 = f32(m[10]), a32 = f32(m[14]),
1175               a03 = f32(m[3]), a13 = f32(m[7]), a23 = f32(m[11]), a33 = f32(m[15]);
1176 
1177     skvm::F32 b00 = a00**a11 - a01**a10,
1178               b01 = a00**a12 - a02**a10,
1179               b02 = a00**a13 - a03**a10,
1180               b03 = a01**a12 - a02**a11,
1181               b04 = a01**a13 - a03**a11,
1182               b05 = a02**a13 - a03**a12,
1183               b06 = a20**a31 - a21**a30,
1184               b07 = a20**a32 - a22**a30,
1185               b08 = a20**a33 - a23**a30,
1186               b09 = a21**a32 - a22**a31,
1187               b10 = a21**a33 - a23**a31,
1188               b11 = a22**a33 - a23**a32;
1189 
1190     skvm::F32 idet = 1.0f / (b00**b11 - b01**b10 + b02**b09 + b03**b08 - b04**b07 + b05**b06);
1191 
1192     b00 *= idet;
1193     b01 *= idet;
1194     b02 *= idet;
1195     b03 *= idet;
1196     b04 *= idet;
1197     b05 *= idet;
1198     b06 *= idet;
1199     b07 *= idet;
1200     b08 *= idet;
1201     b09 *= idet;
1202     b10 *= idet;
1203     b11 *= idet;
1204 
1205     Value result(m.slots());
1206     result[ 0] = (a11*b11 - a12*b10 + a13*b09);
1207     result[ 1] = (a02*b10 - a01*b11 - a03*b09);
1208     result[ 2] = (a31*b05 - a32*b04 + a33*b03);
1209     result[ 3] = (a22*b04 - a21*b05 - a23*b03);
1210     result[ 4] = (a12*b08 - a10*b11 - a13*b07);
1211     result[ 5] = (a00*b11 - a02*b08 + a03*b07);
1212     result[ 6] = (a32*b02 - a30*b05 - a33*b01);
1213     result[ 7] = (a20*b05 - a22*b02 + a23*b01);
1214     result[ 8] = (a10*b10 - a11*b08 + a13*b06);
1215     result[ 9] = (a01*b08 - a00*b10 - a03*b06);
1216     result[10] = (a30*b04 - a31*b02 + a33*b00);
1217     result[11] = (a21*b02 - a20*b04 - a23*b00);
1218     result[12] = (a11*b07 - a10*b09 - a12*b06);
1219     result[13] = (a00*b09 - a01*b07 + a02*b06);
1220     result[14] = (a31*b01 - a30*b03 - a32*b00);
1221     result[15] = (a20*b03 - a21*b01 + a22*b00);
1222     return result;
1223 }
1224 
writeChildCall(const ChildCall & c)1225 Value SkVMGenerator::writeChildCall(const ChildCall& c) {
1226     auto child_it = fVariableMap.find(&c.child());
1227     SkASSERT(child_it != fVariableMap.end());
1228 
1229     const Expression* arg = c.arguments()[0].get();
1230     Value argVal = this->writeExpression(*arg);
1231     skvm::Color color;
1232 
1233     switch (c.child().type().typeKind()) {
1234         case Type::TypeKind::kShader: {
1235             SkASSERT(c.arguments().size() == 1);
1236             SkASSERT(arg->type().matches(*fProgram.fContext->fTypes.fFloat2));
1237             skvm::Coord coord = {f32(argVal[0]), f32(argVal[1])};
1238             color = fCallbacks->sampleShader(child_it->second, coord);
1239             break;
1240         }
1241         case Type::TypeKind::kColorFilter: {
1242             SkASSERT(c.arguments().size() == 1);
1243             SkASSERT(arg->type().matches(*fProgram.fContext->fTypes.fHalf4) ||
1244                      arg->type().matches(*fProgram.fContext->fTypes.fFloat4));
1245             skvm::Color inColor = {f32(argVal[0]), f32(argVal[1]), f32(argVal[2]), f32(argVal[3])};
1246             color = fCallbacks->sampleColorFilter(child_it->second, inColor);
1247             break;
1248         }
1249         case Type::TypeKind::kBlender: {
1250             SkASSERT(c.arguments().size() == 2);
1251             SkASSERT(arg->type().matches(*fProgram.fContext->fTypes.fHalf4) ||
1252                      arg->type().matches(*fProgram.fContext->fTypes.fFloat4));
1253             skvm::Color srcColor = {f32(argVal[0]), f32(argVal[1]), f32(argVal[2]), f32(argVal[3])};
1254 
1255             arg = c.arguments()[1].get();
1256             argVal = this->writeExpression(*arg);
1257             SkASSERT(arg->type().matches(*fProgram.fContext->fTypes.fHalf4) ||
1258                      arg->type().matches(*fProgram.fContext->fTypes.fFloat4));
1259             skvm::Color dstColor = {f32(argVal[0]), f32(argVal[1]), f32(argVal[2]), f32(argVal[3])};
1260 
1261             color = fCallbacks->sampleBlender(child_it->second, srcColor, dstColor);
1262             break;
1263         }
1264         default: {
1265             SkDEBUGFAILF("cannot sample from type '%s'", c.child().type().description().c_str());
1266         }
1267     }
1268 
1269     Value result(4);
1270     result[0] = color.r;
1271     result[1] = color.g;
1272     result[2] = color.b;
1273     result[3] = color.a;
1274     return result;
1275 }
1276 
writeIntrinsicCall(const FunctionCall & c)1277 Value SkVMGenerator::writeIntrinsicCall(const FunctionCall& c) {
1278     IntrinsicKind intrinsicKind = c.function().intrinsicKind();
1279     SkASSERT(intrinsicKind != kNotIntrinsic);
1280 
1281     const size_t nargs = c.arguments().size();
1282     const size_t kMaxArgs = 3;  // eg: clamp, mix, smoothstep
1283     Value args[kMaxArgs];
1284     SkASSERT(nargs >= 1 && nargs <= SK_ARRAY_COUNT(args));
1285 
1286     // All other intrinsics have at most three args, and those can all be evaluated up front:
1287     for (size_t i = 0; i < nargs; ++i) {
1288         args[i] = this->writeExpression(*c.arguments()[i]);
1289     }
1290     Type::NumberKind nk = base_number_kind(c.arguments()[0]->type());
1291 
1292     auto binary = [&](auto&& fn) {
1293         // Binary intrinsics are (vecN, vecN), (vecN, float), or (float, vecN)
1294         size_t nslots = std::max(args[0].slots(), args[1].slots());
1295         Value result(nslots);
1296         SkASSERT(args[0].slots() == nslots || args[0].slots() == 1);
1297         SkASSERT(args[1].slots() == nslots || args[1].slots() == 1);
1298 
1299         for (size_t i = 0; i < nslots; ++i) {
1300             result[i] = fn({fBuilder, args[0][args[0].slots() == 1 ? 0 : i]},
1301                            {fBuilder, args[1][args[1].slots() == 1 ? 0 : i]});
1302         }
1303         return result;
1304     };
1305 
1306     auto ternary = [&](auto&& fn) {
1307         // Ternary intrinsics are some combination of vecN and float
1308         size_t nslots = std::max({args[0].slots(), args[1].slots(), args[2].slots()});
1309         Value result(nslots);
1310         SkASSERT(args[0].slots() == nslots || args[0].slots() == 1);
1311         SkASSERT(args[1].slots() == nslots || args[1].slots() == 1);
1312         SkASSERT(args[2].slots() == nslots || args[2].slots() == 1);
1313 
1314         for (size_t i = 0; i < nslots; ++i) {
1315             result[i] = fn({fBuilder, args[0][args[0].slots() == 1 ? 0 : i]},
1316                            {fBuilder, args[1][args[1].slots() == 1 ? 0 : i]},
1317                            {fBuilder, args[2][args[2].slots() == 1 ? 0 : i]});
1318         }
1319         return result;
1320     };
1321 
1322     auto dot = [&](const Value& x, const Value& y) {
1323         SkASSERT(x.slots() == y.slots());
1324         skvm::F32 result = f32(x[0]) * f32(y[0]);
1325         for (size_t i = 1; i < x.slots(); ++i) {
1326             result += f32(x[i]) * f32(y[i]);
1327         }
1328         return result;
1329     };
1330 
1331     switch (intrinsicKind) {
1332         case k_radians_IntrinsicKind:
1333             return unary(args[0], [](skvm::F32 deg) { return deg * (SK_FloatPI / 180); });
1334         case k_degrees_IntrinsicKind:
1335             return unary(args[0], [](skvm::F32 rad) { return rad * (180 / SK_FloatPI); });
1336 
1337         case k_sin_IntrinsicKind: return unary(args[0], skvm::approx_sin);
1338         case k_cos_IntrinsicKind: return unary(args[0], skvm::approx_cos);
1339         case k_tan_IntrinsicKind: return unary(args[0], skvm::approx_tan);
1340 
1341         case k_asin_IntrinsicKind: return unary(args[0], skvm::approx_asin);
1342         case k_acos_IntrinsicKind: return unary(args[0], skvm::approx_acos);
1343 
1344         case k_atan_IntrinsicKind: return nargs == 1 ? unary(args[0], skvm::approx_atan)
1345                                                  : binary(skvm::approx_atan2);
1346 
1347         case k_pow_IntrinsicKind:
1348             return binary([](skvm::F32 x, skvm::F32 y) { return skvm::approx_powf(x, y); });
1349         case k_exp_IntrinsicKind:  return unary(args[0], skvm::approx_exp);
1350         case k_log_IntrinsicKind:  return unary(args[0], skvm::approx_log);
1351         case k_exp2_IntrinsicKind: return unary(args[0], skvm::approx_pow2);
1352         case k_log2_IntrinsicKind: return unary(args[0], skvm::approx_log2);
1353 
1354         case k_sqrt_IntrinsicKind: return unary(args[0], skvm::sqrt);
1355         case k_inversesqrt_IntrinsicKind:
1356             return unary(args[0], [](skvm::F32 x) { return 1.0f / skvm::sqrt(x); });
1357 
1358         case k_abs_IntrinsicKind: return unary(args[0], skvm::abs);
1359         case k_sign_IntrinsicKind:
1360             return unary(args[0], [](skvm::F32 x) { return select(x < 0, -1.0f,
1361                                                            select(x > 0, +1.0f, 0.0f)); });
1362         case k_floor_IntrinsicKind: return unary(args[0], skvm::floor);
1363         case k_ceil_IntrinsicKind:  return unary(args[0], skvm::ceil);
1364         case k_fract_IntrinsicKind: return unary(args[0], skvm::fract);
1365         case k_mod_IntrinsicKind:
1366             return binary([](skvm::F32 x, skvm::F32 y) { return x - y*skvm::floor(x / y); });
1367 
1368         case k_min_IntrinsicKind:
1369             return binary([](skvm::F32 x, skvm::F32 y) { return skvm::min(x, y); });
1370         case k_max_IntrinsicKind:
1371             return binary([](skvm::F32 x, skvm::F32 y) { return skvm::max(x, y); });
1372         case k_clamp_IntrinsicKind:
1373             return ternary(
1374                     [](skvm::F32 x, skvm::F32 lo, skvm::F32 hi) { return skvm::clamp(x, lo, hi); });
1375         case k_saturate_IntrinsicKind:
1376             return unary(args[0], [](skvm::F32 x) { return skvm::clamp01(x); });
1377         case k_mix_IntrinsicKind:
1378             return ternary(
1379                     [](skvm::F32 x, skvm::F32 y, skvm::F32 t) { return skvm::lerp(x, y, t); });
1380         case k_step_IntrinsicKind:
1381             return binary([](skvm::F32 edge, skvm::F32 x) { return select(x < edge, 0.0f, 1.0f); });
1382         case k_smoothstep_IntrinsicKind:
1383             return ternary([](skvm::F32 edge0, skvm::F32 edge1, skvm::F32 x) {
1384                 skvm::F32 t = skvm::clamp01((x - edge0) / (edge1 - edge0));
1385                 return t ** t ** (3 - 2 ** t);
1386             });
1387 
1388         case k_length_IntrinsicKind: return skvm::sqrt(dot(args[0], args[0]));
1389         case k_distance_IntrinsicKind: {
1390             Value vec = binary([](skvm::F32 x, skvm::F32 y) { return x - y; });
1391             return skvm::sqrt(dot(vec, vec));
1392         }
1393         case k_dot_IntrinsicKind: return dot(args[0], args[1]);
1394         case k_cross_IntrinsicKind: {
1395             skvm::F32 ax = f32(args[0][0]), ay = f32(args[0][1]), az = f32(args[0][2]),
1396                       bx = f32(args[1][0]), by = f32(args[1][1]), bz = f32(args[1][2]);
1397             Value result(3);
1398             result[0] = ay**bz - az**by;
1399             result[1] = az**bx - ax**bz;
1400             result[2] = ax**by - ay**bx;
1401             return result;
1402         }
1403         case k_normalize_IntrinsicKind: {
1404             skvm::F32 invLen = 1.0f / skvm::sqrt(dot(args[0], args[0]));
1405             return unary(args[0], [&](skvm::F32 x) { return x ** invLen; });
1406         }
1407         case k_faceforward_IntrinsicKind: {
1408             const Value &N    = args[0],
1409                         &I    = args[1],
1410                         &Nref = args[2];
1411 
1412             skvm::F32 dotNrefI = dot(Nref, I);
1413             return unary(N, [&](skvm::F32 n) { return select(dotNrefI<0, n, -n); });
1414         }
1415         case k_reflect_IntrinsicKind: {
1416             const Value &I = args[0],
1417                         &N = args[1];
1418 
1419             skvm::F32 dotNI = dot(N, I);
1420             return binary([&](skvm::F32 i, skvm::F32 n) {
1421                 return i - 2**dotNI**n;
1422             });
1423         }
1424         case k_refract_IntrinsicKind: {
1425             const Value &I  = args[0],
1426                         &N  = args[1];
1427             skvm::F32   eta = f32(args[2]);
1428 
1429             skvm::F32 dotNI = dot(N, I),
1430                       k     = 1 - eta**eta**(1 - dotNI**dotNI);
1431             return binary([&](skvm::F32 i, skvm::F32 n) {
1432                 return select(k<0, 0.0f, eta**i - (eta**dotNI + sqrt(k))**n);
1433             });
1434         }
1435 
1436         case k_matrixCompMult_IntrinsicKind:
1437             return binary([](skvm::F32 x, skvm::F32 y) { return x ** y; });
1438         case k_inverse_IntrinsicKind: {
1439             switch (args[0].slots()) {
1440                 case  4: return this->writeMatrixInverse2x2(args[0]);
1441                 case  9: return this->writeMatrixInverse3x3(args[0]);
1442                 case 16: return this->writeMatrixInverse4x4(args[0]);
1443                 default:
1444                     SkDEBUGFAIL("Invalid call to inverse");
1445                     return {};
1446             }
1447         }
1448 
1449         case k_lessThan_IntrinsicKind:
1450             return nk == Type::NumberKind::kFloat
1451                            ? binary([](skvm::F32 x, skvm::F32 y) { return x < y; })
1452                            : binary([](skvm::I32 x, skvm::I32 y) { return x < y; });
1453         case k_lessThanEqual_IntrinsicKind:
1454             return nk == Type::NumberKind::kFloat
1455                            ? binary([](skvm::F32 x, skvm::F32 y) { return x <= y; })
1456                            : binary([](skvm::I32 x, skvm::I32 y) { return x <= y; });
1457         case k_greaterThan_IntrinsicKind:
1458             return nk == Type::NumberKind::kFloat
1459                            ? binary([](skvm::F32 x, skvm::F32 y) { return x > y; })
1460                            : binary([](skvm::I32 x, skvm::I32 y) { return x > y; });
1461         case k_greaterThanEqual_IntrinsicKind:
1462             return nk == Type::NumberKind::kFloat
1463                            ? binary([](skvm::F32 x, skvm::F32 y) { return x >= y; })
1464                            : binary([](skvm::I32 x, skvm::I32 y) { return x >= y; });
1465 
1466         case k_equal_IntrinsicKind:
1467             return nk == Type::NumberKind::kFloat
1468                            ? binary([](skvm::F32 x, skvm::F32 y) { return x == y; })
1469                            : binary([](skvm::I32 x, skvm::I32 y) { return x == y; });
1470         case k_notEqual_IntrinsicKind:
1471             return nk == Type::NumberKind::kFloat
1472                            ? binary([](skvm::F32 x, skvm::F32 y) { return x != y; })
1473                            : binary([](skvm::I32 x, skvm::I32 y) { return x != y; });
1474 
1475         case k_any_IntrinsicKind: {
1476             skvm::I32 result = i32(args[0][0]);
1477             for (size_t i = 1; i < args[0].slots(); ++i) {
1478                 result |= i32(args[0][i]);
1479             }
1480             return result;
1481         }
1482         case k_all_IntrinsicKind: {
1483             skvm::I32 result = i32(args[0][0]);
1484             for (size_t i = 1; i < args[0].slots(); ++i) {
1485                 result &= i32(args[0][i]);
1486             }
1487             return result;
1488         }
1489         case k_not_IntrinsicKind: return unary(args[0], [](skvm::I32 x) { return ~x; });
1490 
1491         case k_toLinearSrgb_IntrinsicKind: {
1492             skvm::Color color = {
1493                     f32(args[0][0]), f32(args[0][1]), f32(args[0][2]), fBuilder->splat(1.0f)};
1494             color = fCallbacks->toLinearSrgb(color);
1495             Value result(3);
1496             result[0] = color.r;
1497             result[1] = color.g;
1498             result[2] = color.b;
1499             return result;
1500         }
1501         case k_fromLinearSrgb_IntrinsicKind: {
1502             skvm::Color color = {
1503                     f32(args[0][0]), f32(args[0][1]), f32(args[0][2]), fBuilder->splat(1.0f)};
1504             color = fCallbacks->fromLinearSrgb(color);
1505             Value result(3);
1506             result[0] = color.r;
1507             result[1] = color.g;
1508             result[2] = color.b;
1509             return result;
1510         }
1511 
1512         default:
1513             SkDEBUGFAILF("unsupported intrinsic %s", c.function().description().c_str());
1514             return {};
1515     }
1516     SkUNREACHABLE;
1517 }
1518 
writeFunctionCall(const FunctionCall & f)1519 Value SkVMGenerator::writeFunctionCall(const FunctionCall& f) {
1520     if (f.function().isIntrinsic() && !f.function().definition()) {
1521         return this->writeIntrinsicCall(f);
1522     }
1523 
1524     const FunctionDeclaration& decl = f.function();
1525     SkASSERTF(decl.definition(), "no definition for function '%s'", decl.description().c_str());
1526     const FunctionDefinition& funcDef = *decl.definition();
1527 
1528     // Evaluate all arguments, gather the results into a contiguous list of IDs
1529     std::vector<skvm::Val> argVals;
1530     for (const auto& arg : f.arguments()) {
1531         Value v = this->writeExpression(*arg);
1532         for (size_t i = 0; i < v.slots(); ++i) {
1533             argVals.push_back(v[i]);
1534         }
1535     }
1536 
1537     size_t returnSlot;
1538     {
1539         // This merges currentFunction().fReturned into fConditionMask. Lanes that conditionally
1540         // returned in the current function would otherwise resume execution within the child.
1541         ScopedCondition m(this, ~currentFunction().fReturned);
1542         returnSlot = this->writeFunction(funcDef, SkMakeSpan(argVals));
1543     }
1544 
1545     // Propagate new values of any 'out' params back to the original arguments
1546     const std::unique_ptr<Expression>* argIter = f.arguments().begin();
1547     size_t valIdx = 0;
1548     for (const Variable* p : decl.parameters()) {
1549         size_t nslots = p->type().slotCount();
1550         if (p->modifiers().fFlags & Modifiers::kOut_Flag) {
1551             Value v(nslots);
1552             for (size_t i = 0; i < nslots; ++i) {
1553                 v[i] = argVals[valIdx + i];
1554             }
1555             const std::unique_ptr<Expression>& arg = *argIter;
1556             this->writeStore(*arg, v);
1557         }
1558         valIdx += nslots;
1559         argIter++;
1560     }
1561 
1562     // Create a result Value from the return slot
1563     return this->getSlotValue(returnSlot, f.type().slotCount());
1564 }
1565 
writeExternalFunctionCall(const ExternalFunctionCall & c)1566 Value SkVMGenerator::writeExternalFunctionCall(const ExternalFunctionCall& c) {
1567     // Evaluate all arguments, gather the results into a contiguous list of F32
1568     std::vector<skvm::F32> args;
1569     for (const auto& arg : c.arguments()) {
1570         Value v = this->writeExpression(*arg);
1571         for (size_t i = 0; i < v.slots(); ++i) {
1572             args.push_back(f32(v[i]));
1573         }
1574     }
1575 
1576     // Create storage for the return value
1577     size_t nslots = c.type().slotCount();
1578     std::vector<skvm::F32> result(nslots, fBuilder->splat(0.0f));
1579 
1580     c.function().call(fBuilder, args.data(), result.data(), this->mask());
1581 
1582     // Convert from 'vector of F32' to Value
1583     Value resultVal(nslots);
1584     for (size_t i = 0; i < nslots; ++i) {
1585         resultVal[i] = result[i];
1586     }
1587 
1588     return resultVal;
1589 }
1590 
writeLiteral(const Literal & l)1591 Value SkVMGenerator::writeLiteral(const Literal& l) {
1592     if (l.type().isFloat()) {
1593         return fBuilder->splat(l.as<Literal>().floatValue());
1594     }
1595     if (l.type().isInteger()) {
1596         return fBuilder->splat(static_cast<int>(l.as<Literal>().intValue()));
1597     }
1598     SkASSERT(l.type().isBoolean());
1599     return fBuilder->splat(l.as<Literal>().boolValue() ? ~0 : 0);
1600 }
1601 
writePrefixExpression(const PrefixExpression & p)1602 Value SkVMGenerator::writePrefixExpression(const PrefixExpression& p) {
1603     Value val = this->writeExpression(*p.operand());
1604 
1605     switch (p.getOperator().kind()) {
1606         case Token::Kind::TK_PLUSPLUS:
1607         case Token::Kind::TK_MINUSMINUS: {
1608             bool incr = p.getOperator().kind() == Token::Kind::TK_PLUSPLUS;
1609 
1610             switch (base_number_kind(p.type())) {
1611                 case Type::NumberKind::kFloat:
1612                     val = f32(val) + fBuilder->splat(incr ? 1.0f : -1.0f);
1613                     break;
1614                 case Type::NumberKind::kSigned:
1615                     val = i32(val) + fBuilder->splat(incr ? 1 : -1);
1616                     break;
1617                 default:
1618                     SkASSERT(false);
1619                     return {};
1620             }
1621             return this->writeStore(*p.operand(), val);
1622         }
1623         case Token::Kind::TK_MINUS: {
1624             switch (base_number_kind(p.type())) {
1625                 case Type::NumberKind::kFloat:
1626                     return this->unary(val, [](skvm::F32 x) { return -x; });
1627                 case Type::NumberKind::kSigned:
1628                     return this->unary(val, [](skvm::I32 x) { return -x; });
1629                 default:
1630                     SkASSERT(false);
1631                     return {};
1632             }
1633         }
1634         case Token::Kind::TK_LOGICALNOT:
1635         case Token::Kind::TK_BITWISENOT:
1636             return this->unary(val, [](skvm::I32 x) { return ~x; });
1637         default:
1638             SkASSERT(false);
1639             return {};
1640     }
1641 }
1642 
writePostfixExpression(const PostfixExpression & p)1643 Value SkVMGenerator::writePostfixExpression(const PostfixExpression& p) {
1644     switch (p.getOperator().kind()) {
1645         case Token::Kind::TK_PLUSPLUS:
1646         case Token::Kind::TK_MINUSMINUS: {
1647             Value old = this->writeExpression(*p.operand()),
1648                   val = old;
1649             SkASSERT(val.slots() == 1);
1650             bool incr = p.getOperator().kind() == Token::Kind::TK_PLUSPLUS;
1651 
1652             switch (base_number_kind(p.type())) {
1653                 case Type::NumberKind::kFloat:
1654                     val = f32(val) + fBuilder->splat(incr ? 1.0f : -1.0f);
1655                     break;
1656                 case Type::NumberKind::kSigned:
1657                     val = i32(val) + fBuilder->splat(incr ? 1 : -1);
1658                     break;
1659                 default:
1660                     SkASSERT(false);
1661                     return {};
1662             }
1663             this->writeStore(*p.operand(), val);
1664             return old;
1665         }
1666         default:
1667             SkASSERT(false);
1668             return {};
1669     }
1670 }
1671 
writeSwizzle(const Swizzle & s)1672 Value SkVMGenerator::writeSwizzle(const Swizzle& s) {
1673     Value base = this->writeExpression(*s.base());
1674     Value swizzled(s.components().size());
1675     for (size_t i = 0; i < s.components().size(); ++i) {
1676         swizzled[i] = base[s.components()[i]];
1677     }
1678     return swizzled;
1679 }
1680 
writeTernaryExpression(const TernaryExpression & t)1681 Value SkVMGenerator::writeTernaryExpression(const TernaryExpression& t) {
1682     skvm::I32 test = i32(this->writeExpression(*t.test()));
1683     Value ifTrue, ifFalse;
1684 
1685     {
1686         ScopedCondition m(this, test);
1687         ifTrue = this->writeExpression(*t.ifTrue());
1688     }
1689     {
1690         ScopedCondition m(this, ~test);
1691         ifFalse = this->writeExpression(*t.ifFalse());
1692     }
1693 
1694     size_t nslots = ifTrue.slots();
1695     SkASSERT(nslots == ifFalse.slots());
1696 
1697     Value result(nslots);
1698     for (size_t i = 0; i < nslots; ++i) {
1699         result[i] = skvm::select(test, i32(ifTrue[i]), i32(ifFalse[i]));
1700     }
1701     return result;
1702 }
1703 
writeExpression(const Expression & e)1704 Value SkVMGenerator::writeExpression(const Expression& e) {
1705     switch (e.kind()) {
1706         case Expression::Kind::kBinary:
1707             return this->writeBinaryExpression(e.as<BinaryExpression>());
1708         case Expression::Kind::kChildCall:
1709             return this->writeChildCall(e.as<ChildCall>());
1710         case Expression::Kind::kConstructorArray:
1711         case Expression::Kind::kConstructorCompound:
1712         case Expression::Kind::kConstructorStruct:
1713             return this->writeAggregationConstructor(e.asAnyConstructor());
1714         case Expression::Kind::kConstructorArrayCast:
1715             return this->writeExpression(*e.as<ConstructorArrayCast>().argument());
1716         case Expression::Kind::kConstructorDiagonalMatrix:
1717             return this->writeConstructorDiagonalMatrix(e.as<ConstructorDiagonalMatrix>());
1718         case Expression::Kind::kConstructorMatrixResize:
1719             return this->writeConstructorMatrixResize(e.as<ConstructorMatrixResize>());
1720         case Expression::Kind::kConstructorScalarCast:
1721         case Expression::Kind::kConstructorCompoundCast:
1722             return this->writeConstructorCast(e.asAnyConstructor());
1723         case Expression::Kind::kConstructorSplat:
1724             return this->writeConstructorSplat(e.as<ConstructorSplat>());
1725         case Expression::Kind::kFieldAccess:
1726             return this->writeFieldAccess(e.as<FieldAccess>());
1727         case Expression::Kind::kIndex:
1728             return this->writeIndexExpression(e.as<IndexExpression>());
1729         case Expression::Kind::kVariableReference:
1730             return this->writeVariableExpression(e.as<VariableReference>());
1731         case Expression::Kind::kLiteral:
1732             return this->writeLiteral(e.as<Literal>());
1733         case Expression::Kind::kFunctionCall:
1734             return this->writeFunctionCall(e.as<FunctionCall>());
1735         case Expression::Kind::kExternalFunctionCall:
1736             return this->writeExternalFunctionCall(e.as<ExternalFunctionCall>());
1737         case Expression::Kind::kPrefix:
1738             return this->writePrefixExpression(e.as<PrefixExpression>());
1739         case Expression::Kind::kPostfix:
1740             return this->writePostfixExpression(e.as<PostfixExpression>());
1741         case Expression::Kind::kSwizzle:
1742             return this->writeSwizzle(e.as<Swizzle>());
1743         case Expression::Kind::kTernary:
1744             return this->writeTernaryExpression(e.as<TernaryExpression>());
1745         case Expression::Kind::kExternalFunctionReference:
1746         default:
1747             SkDEBUGFAIL("Unsupported expression");
1748             return {};
1749     }
1750 }
1751 
writeStore(const Expression & lhs,const Value & rhs)1752 Value SkVMGenerator::writeStore(const Expression& lhs, const Value& rhs) {
1753     SkASSERTF(rhs.slots() == lhs.type().slotCount(),
1754               "lhs=%s (%s)\nrhs=%zu slot",
1755               lhs.type().description().c_str(), lhs.description().c_str(), rhs.slots());
1756 
1757     // We need to figure out the collection of slots that we're storing into. The l-value (lhs)
1758     // is always a VariableReference, possibly wrapped by one or more Swizzle, FieldAccess, or
1759     // IndexExpressions. The underlying VariableReference has a range of slots for its storage,
1760     // and each expression wrapped around that selects a sub-set of those slots (Field/Index),
1761     // or rearranges them (Swizzle).
1762     SkSTArray<4, size_t, true> slots;
1763     slots.resize(rhs.slots());
1764 
1765     // Start with the identity slot map - this basically says that the values from rhs belong in
1766     // slots [0, 1, 2 ... N] of the lhs.
1767     for (size_t i = 0; i < slots.size(); ++i) {
1768         slots[i] = i;
1769     }
1770 
1771     // Now, as we peel off each outer expression, adjust 'slots' to be the locations relative to
1772     // the next (inner) expression:
1773     const Expression* expr = &lhs;
1774     while (!expr->is<VariableReference>()) {
1775         switch (expr->kind()) {
1776             case Expression::Kind::kFieldAccess: {
1777                 const FieldAccess& fld = expr->as<FieldAccess>();
1778                 size_t offset = this->fieldSlotOffset(fld);
1779                 for (size_t& s : slots) {
1780                     s += offset;
1781                 }
1782                 expr = fld.base().get();
1783             } break;
1784             case Expression::Kind::kIndex: {
1785                 const IndexExpression& idx = expr->as<IndexExpression>();
1786                 size_t offset = this->indexSlotOffset(idx);
1787                 for (size_t& s : slots) {
1788                     s += offset;
1789                 }
1790                 expr = idx.base().get();
1791             } break;
1792             case Expression::Kind::kSwizzle: {
1793                 const Swizzle& swz = expr->as<Swizzle>();
1794                 for (size_t& s : slots) {
1795                     s = swz.components()[s];
1796                 }
1797                 expr = swz.base().get();
1798             } break;
1799             default:
1800                 // No other kinds of expressions are valid in lvalues. (see Analysis::IsAssignable)
1801                 SkDEBUGFAIL("Invalid expression type");
1802                 return {};
1803         }
1804     }
1805 
1806     // When we get here, 'slots' are all relative to the first slot holding 'var's storage
1807     const Variable& var = *expr->as<VariableReference>().variable();
1808     size_t varSlot = this->getSlot(var);
1809     for (size_t& slot : slots) {
1810         SkASSERT(slot < var.type().slotCount());
1811         slot += varSlot;
1812     }
1813 
1814     // `slots` are now absolute indices into `fSlots`.
1815     skvm::I32 mask = this->mask();
1816     for (size_t i = 0; i < rhs.slots(); ++i) {
1817         int slotNum = slots[i];
1818         skvm::Val conditionalStore = this->writeConditionalStore(fSlots[slotNum].val, rhs[i], mask);
1819         this->writeToSlot(slotNum, conditionalStore);
1820     }
1821 
1822     return rhs;
1823 }
1824 
writeConditionalStore(skvm::Val lhs,skvm::Val rhs,skvm::I32 mask)1825 skvm::Val SkVMGenerator::writeConditionalStore(skvm::Val lhs, skvm::Val rhs, skvm::I32 mask) {
1826     return select(mask, f32(rhs), f32(lhs)).id;
1827 }
1828 
writeBlock(const Block & b)1829 void SkVMGenerator::writeBlock(const Block& b) {
1830     skvm::I32 mask = this->mask();
1831     if (b.isScope()) {
1832         this->emitTraceScope(mask, +1);
1833     }
1834 
1835     for (const std::unique_ptr<Statement>& stmt : b.children()) {
1836         this->writeStatement(*stmt);
1837     }
1838 
1839     if (b.isScope()) {
1840         this->emitTraceScope(mask, -1);
1841     }
1842 }
1843 
writeBreakStatement()1844 void SkVMGenerator::writeBreakStatement() {
1845     // Any active lanes stop executing for the duration of the current loop
1846     fLoopMask &= ~this->mask();
1847 }
1848 
writeContinueStatement()1849 void SkVMGenerator::writeContinueStatement() {
1850     // Any active lanes stop executing for the current iteration.
1851     // Remember them in fContinueMask, to be re-enabled later.
1852     skvm::I32 mask = this->mask();
1853     fLoopMask &= ~mask;
1854     fContinueMask |= mask;
1855 }
1856 
writeForStatement(const ForStatement & f)1857 void SkVMGenerator::writeForStatement(const ForStatement& f) {
1858     // We require that all loops be ES2-compliant (unrollable), and actually unroll them here
1859     SkASSERT(f.unrollInfo());
1860     const LoopUnrollInfo& loop = *f.unrollInfo();
1861     SkASSERT(loop.fIndex->type().slotCount() == 1);
1862 
1863     size_t indexSlot = this->getSlot(*loop.fIndex);
1864     double val = loop.fStart;
1865 
1866     const skvm::I32 zero      = fBuilder->splat(0);
1867     skvm::I32 oldLoopMask     = fLoopMask,
1868               oldContinueMask = fContinueMask;
1869 
1870     const Type::NumberKind indexKind = base_number_kind(loop.fIndex->type());
1871 
1872     // We want the loop index to disappear at the end of the loop, so wrap the for statement in a
1873     // trace scope.
1874     if (loop.fCount > 0) {
1875         skvm::I32 mask = this->mask();
1876         this->emitTraceScope(mask, +1);
1877 
1878         for (int i = 0; i < loop.fCount; ++i) {
1879             this->writeToSlot(indexSlot, (indexKind == Type::NumberKind::kFloat)
1880                                             ? fBuilder->splat(static_cast<float>(val)).id
1881                                             : fBuilder->splat(static_cast<int>(val)).id);
1882 
1883             fContinueMask = zero;
1884             this->writeStatement(*f.statement());
1885             fLoopMask |= fContinueMask;
1886 
1887             this->emitTraceLine(f.test() ? f.test()->fLine : f.fLine);
1888             val += loop.fDelta;
1889         }
1890 
1891         this->emitTraceScope(mask, -1);
1892     }
1893 
1894     fLoopMask     = oldLoopMask;
1895     fContinueMask = oldContinueMask;
1896 }
1897 
writeIfStatement(const IfStatement & i)1898 void SkVMGenerator::writeIfStatement(const IfStatement& i) {
1899     Value test = this->writeExpression(*i.test());
1900     {
1901         ScopedCondition ifTrue(this, i32(test));
1902         this->writeStatement(*i.ifTrue());
1903     }
1904     if (i.ifFalse()) {
1905         ScopedCondition ifFalse(this, ~i32(test));
1906         this->writeStatement(*i.ifFalse());
1907     }
1908 }
1909 
writeReturnStatement(const ReturnStatement & r)1910 void SkVMGenerator::writeReturnStatement(const ReturnStatement& r) {
1911     skvm::I32 returnsHere = this->mask();
1912 
1913     if (r.expression()) {
1914         Value val = this->writeExpression(*r.expression());
1915 
1916         size_t slot = currentFunction().fReturnSlot;
1917         size_t nslots = r.expression()->type().slotCount();
1918         for (size_t i = 0; i < nslots; ++i) {
1919             fSlots[slot + i].writtenTo = false;
1920             skvm::Val conditionalStore = this->writeConditionalStore(fSlots[slot + i].val, val[i],
1921                                                                      returnsHere);
1922             this->writeToSlot(slot + i, conditionalStore);
1923         }
1924     }
1925 
1926     currentFunction().fReturned |= returnsHere;
1927 }
1928 
writeSwitchStatement(const SwitchStatement & s)1929 void SkVMGenerator::writeSwitchStatement(const SwitchStatement& s) {
1930     skvm::I32 falseValue = fBuilder->splat( 0);
1931     skvm::I32 trueValue  = fBuilder->splat(~0);
1932 
1933     // Create a "switchFallthough" scratch variable, initialized to false.
1934     skvm::I32 switchFallthrough = falseValue;
1935 
1936     // Loop masks behave just like for statements. When a break is encountered, it masks off all
1937     // lanes for the rest of the body of the switch.
1938     skvm::I32 oldLoopMask       = fLoopMask;
1939     Value switchValue           = this->writeExpression(*s.value());
1940 
1941     for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1942         const SwitchCase& c = stmt->as<SwitchCase>();
1943         if (!c.isDefault()) {
1944             Value caseValue = fBuilder->splat((int) c.value());
1945 
1946             // We want to execute this switch case if we're falling through from a previous case, or
1947             // if the case value matches.
1948             ScopedCondition conditionalCaseBlock(
1949                     this,
1950                     switchFallthrough | (i32(caseValue) == i32(switchValue)));
1951             this->writeStatement(*c.statement());
1952 
1953             // If we are inside the case block, we set the fallthrough flag to true (`break` still
1954             // works to stop the flow of execution regardless, since it zeroes out the loop-mask).
1955             switchFallthrough.id = this->writeConditionalStore(switchFallthrough.id, trueValue.id,
1956                                                                this->mask());
1957         } else {
1958             // This is the default case. Since it's always last, we can just dump in the code.
1959             this->writeStatement(*c.statement());
1960         }
1961     }
1962 
1963     // Restore state.
1964     fLoopMask = oldLoopMask;
1965 }
1966 
writeVarDeclaration(const VarDeclaration & decl)1967 void SkVMGenerator::writeVarDeclaration(const VarDeclaration& decl) {
1968     size_t slot   = this->getSlot(decl.var()),
1969            nslots = decl.var().type().slotCount();
1970 
1971     Value val = decl.value() ? this->writeExpression(*decl.value()) : Value{};
1972     for (size_t i = 0; i < nslots; ++i) {
1973         fSlots[slot + i].writtenTo = false;
1974         this->writeToSlot(slot + i, val ? val[i] : fBuilder->splat(0.0f).id);
1975     }
1976 }
1977 
emitTraceLine(int line)1978 void SkVMGenerator::emitTraceLine(int line) {
1979     if (fDebugTrace && line > 0) {
1980         fBuilder->trace_line(fTraceHookID, this->mask(), fTraceMask, line);
1981     }
1982 }
1983 
emitTraceScope(skvm::I32 executionMask,int delta)1984 void SkVMGenerator::emitTraceScope(skvm::I32 executionMask, int delta) {
1985     if (fDebugTrace) {
1986         fBuilder->trace_scope(fTraceHookID, executionMask, fTraceMask, delta);
1987     }
1988 }
1989 
writeStatement(const Statement & s)1990 void SkVMGenerator::writeStatement(const Statement& s) {
1991     this->emitTraceLine(s.fLine);
1992 
1993     switch (s.kind()) {
1994         case Statement::Kind::kBlock:
1995             this->writeBlock(s.as<Block>());
1996             break;
1997         case Statement::Kind::kBreak:
1998             this->writeBreakStatement();
1999             break;
2000         case Statement::Kind::kContinue:
2001             this->writeContinueStatement();
2002             break;
2003         case Statement::Kind::kExpression:
2004             this->writeExpression(*s.as<ExpressionStatement>().expression());
2005             break;
2006         case Statement::Kind::kFor:
2007             this->writeForStatement(s.as<ForStatement>());
2008             break;
2009         case Statement::Kind::kIf:
2010             this->writeIfStatement(s.as<IfStatement>());
2011             break;
2012         case Statement::Kind::kReturn:
2013             this->writeReturnStatement(s.as<ReturnStatement>());
2014             break;
2015         case Statement::Kind::kSwitch:
2016             this->writeSwitchStatement(s.as<SwitchStatement>());
2017             break;
2018         case Statement::Kind::kVarDeclaration:
2019             this->writeVarDeclaration(s.as<VarDeclaration>());
2020             break;
2021         case Statement::Kind::kDiscard:
2022         case Statement::Kind::kDo:
2023             SkDEBUGFAIL("Unsupported control flow");
2024             break;
2025         case Statement::Kind::kInlineMarker:
2026         case Statement::Kind::kNop:
2027             break;
2028         default:
2029             SkDEBUGFAIL("Unrecognized statement");
2030             break;
2031     }
2032 }
2033 
ProgramToSkVM(const Program & program,const FunctionDefinition & function,skvm::Builder * builder,SkVMDebugTrace * debugTrace,SkSpan<skvm::Val> uniforms,skvm::Coord device,skvm::Coord local,skvm::Color inputColor,skvm::Color destColor,SkVMCallbacks * callbacks)2034 skvm::Color ProgramToSkVM(const Program& program,
2035                           const FunctionDefinition& function,
2036                           skvm::Builder* builder,
2037                           SkVMDebugTrace* debugTrace,
2038                           SkSpan<skvm::Val> uniforms,
2039                           skvm::Coord device,
2040                           skvm::Coord local,
2041                           skvm::Color inputColor,
2042                           skvm::Color destColor,
2043                           SkVMCallbacks* callbacks) {
2044     skvm::Val zero = builder->splat(0.0f).id;
2045     skvm::Val result[4] = {zero,zero,zero,zero};
2046 
2047     skvm::Val args[8];  // At most 8 arguments (half4 srcColor, half4 dstColor)
2048     size_t argSlots = 0;
2049     for (const SkSL::Variable* param : function.declaration().parameters()) {
2050         switch (param->modifiers().fLayout.fBuiltin) {
2051             case SK_MAIN_COORDS_BUILTIN:
2052                 SkASSERT(param->type().slotCount() == 2);
2053                 SkASSERT((argSlots + 2) <= SK_ARRAY_COUNT(args));
2054                 args[argSlots++] = local.x.id;
2055                 args[argSlots++] = local.y.id;
2056                 break;
2057             case SK_INPUT_COLOR_BUILTIN:
2058                 SkASSERT(param->type().slotCount() == 4);
2059                 SkASSERT((argSlots + 4) <= SK_ARRAY_COUNT(args));
2060                 args[argSlots++] = inputColor.r.id;
2061                 args[argSlots++] = inputColor.g.id;
2062                 args[argSlots++] = inputColor.b.id;
2063                 args[argSlots++] = inputColor.a.id;
2064                 break;
2065             case SK_DEST_COLOR_BUILTIN:
2066                 SkASSERT(param->type().slotCount() == 4);
2067                 SkASSERT((argSlots + 4) <= SK_ARRAY_COUNT(args));
2068                 args[argSlots++] = destColor.r.id;
2069                 args[argSlots++] = destColor.g.id;
2070                 args[argSlots++] = destColor.b.id;
2071                 args[argSlots++] = destColor.a.id;
2072                 break;
2073             default:
2074                 SkDEBUGFAIL("Invalid parameter to main()");
2075                 return {};
2076         }
2077     }
2078     SkASSERT(argSlots <= SK_ARRAY_COUNT(args));
2079 
2080     // Make sure that the SkVMDebugTrace starts from a clean slate.
2081     if (debugTrace) {
2082         debugTrace->fSlotInfo.clear();
2083         debugTrace->fFuncInfo.clear();
2084         debugTrace->fTraceInfo.clear();
2085     }
2086 
2087     SkVMGenerator generator(program, builder, debugTrace, callbacks);
2088     generator.writeProgram(uniforms, device, function, {args, argSlots}, SkMakeSpan(result));
2089 
2090     return skvm::Color{{builder, result[0]},
2091                        {builder, result[1]},
2092                        {builder, result[2]},
2093                        {builder, result[3]}};
2094 }
2095 
ProgramToSkVM(const Program & program,const FunctionDefinition & function,skvm::Builder * b,SkVMDebugTrace * debugTrace,SkSpan<skvm::Val> uniforms,SkVMSignature * outSignature)2096 bool ProgramToSkVM(const Program& program,
2097                    const FunctionDefinition& function,
2098                    skvm::Builder* b,
2099                    SkVMDebugTrace* debugTrace,
2100                    SkSpan<skvm::Val> uniforms,
2101                    SkVMSignature* outSignature) {
2102     SkVMSignature ignored,
2103                   *signature = outSignature ? outSignature : &ignored;
2104 
2105     std::vector<skvm::Ptr> argPtrs;
2106     std::vector<skvm::Val> argVals;
2107 
2108     for (const Variable* p : function.declaration().parameters()) {
2109         size_t slots = p->type().slotCount();
2110         signature->fParameterSlots += slots;
2111         for (size_t i = 0; i < slots; ++i) {
2112             argPtrs.push_back(b->varying<float>());
2113             argVals.push_back(b->loadF(argPtrs.back()).id);
2114         }
2115     }
2116 
2117     std::vector<skvm::Ptr> returnPtrs;
2118     std::vector<skvm::Val> returnVals;
2119 
2120     signature->fReturnSlots = function.declaration().returnType().slotCount();
2121     for (size_t i = 0; i < signature->fReturnSlots; ++i) {
2122         returnPtrs.push_back(b->varying<float>());
2123         returnVals.push_back(b->splat(0.0f).id);
2124     }
2125 
2126     class Callbacks : public SkVMCallbacks {
2127     public:
2128         Callbacks(skvm::Color color) : fColor(color) {}
2129 
2130         skvm::Color sampleShader(int, skvm::Coord) override {
2131             fUsedUnsupportedFeatures = true;
2132             return fColor;
2133         }
2134         skvm::Color sampleColorFilter(int, skvm::Color) override {
2135             fUsedUnsupportedFeatures = true;
2136             return fColor;
2137         }
2138         skvm::Color sampleBlender(int, skvm::Color, skvm::Color) override {
2139             fUsedUnsupportedFeatures = true;
2140             return fColor;
2141         }
2142 
2143         skvm::Color toLinearSrgb(skvm::Color) override {
2144             fUsedUnsupportedFeatures = true;
2145             return fColor;
2146         }
2147         skvm::Color fromLinearSrgb(skvm::Color) override {
2148             fUsedUnsupportedFeatures = true;
2149             return fColor;
2150         }
2151 
2152         bool fUsedUnsupportedFeatures = false;
2153         const skvm::Color fColor;
2154     };
2155 
2156     // Set up device coordinates so that the rightmost evaluated pixel will be centered on (0, 0).
2157     // (If the coordinates aren't used, dead-code elimination will optimize this away.)
2158     skvm::F32 pixelCenter = b->splat(0.5f);
2159     skvm::Coord device = {pixelCenter, pixelCenter};
2160     device.x += to_F32(b->splat(1) - b->index());
2161 
2162     skvm::F32 zero = b->splat(0.0f);
2163     skvm::Color sampledColor{zero, zero, zero, zero};
2164     Callbacks callbacks(sampledColor);
2165 
2166     SkVMGenerator generator(program, b, debugTrace, &callbacks);
2167     generator.writeProgram(uniforms, device, function, SkMakeSpan(argVals), SkMakeSpan(returnVals));
2168 
2169     // If the SkSL tried to use any shader, colorFilter, or blender objects - we don't have a
2170     // mechanism (yet) for binding to those.
2171     if (callbacks.fUsedUnsupportedFeatures) {
2172         return false;
2173     }
2174 
2175     // generateCode has updated the contents of 'argVals' for any 'out' or 'inout' parameters.
2176     // Propagate those changes back to our varying buffers:
2177     size_t argIdx = 0;
2178     for (const Variable* p : function.declaration().parameters()) {
2179         size_t nslots = p->type().slotCount();
2180         if (p->modifiers().fFlags & Modifiers::kOut_Flag) {
2181             for (size_t i = 0; i < nslots; ++i) {
2182                 b->storeF(argPtrs[argIdx + i], skvm::F32{b, argVals[argIdx + i]});
2183             }
2184         }
2185         argIdx += nslots;
2186     }
2187 
2188     // It's also updated the contents of 'returnVals' with the return value of the entry point.
2189     // Store that as well:
2190     for (size_t i = 0; i < signature->fReturnSlots; ++i) {
2191         b->storeF(returnPtrs[i], skvm::F32{b, returnVals[i]});
2192     }
2193 
2194     return true;
2195 }
2196 
Program_GetFunction(const Program & program,const char * function)2197 const FunctionDefinition* Program_GetFunction(const Program& program, const char* function) {
2198     for (const ProgramElement* e : program.elements()) {
2199         if (e->is<FunctionDefinition>() &&
2200             e->as<FunctionDefinition>().declaration().name() == function) {
2201             return &e->as<FunctionDefinition>();
2202         }
2203     }
2204     return nullptr;
2205 }
2206 
gather_uniforms(UniformInfo * info,const Type & type,const std::string & name)2207 static void gather_uniforms(UniformInfo* info, const Type& type, const std::string& name) {
2208     switch (type.typeKind()) {
2209         case Type::TypeKind::kStruct:
2210             for (const auto& f : type.fields()) {
2211                 gather_uniforms(info, *f.fType, name + "." + std::string(f.fName));
2212             }
2213             break;
2214         case Type::TypeKind::kArray:
2215             for (int i = 0; i < type.columns(); ++i) {
2216                 gather_uniforms(info, type.componentType(),
2217                                 String::printf("%s[%d]", name.c_str(), i));
2218             }
2219             break;
2220         case Type::TypeKind::kScalar:
2221         case Type::TypeKind::kVector:
2222         case Type::TypeKind::kMatrix:
2223             info->fUniforms.push_back({name, base_number_kind(type), type.rows(), type.columns(),
2224                                        info->fUniformSlotCount});
2225             info->fUniformSlotCount += type.columns() * type.rows();
2226             break;
2227         default:
2228             break;
2229     }
2230 }
2231 
Program_GetUniformInfo(const Program & program)2232 std::unique_ptr<UniformInfo> Program_GetUniformInfo(const Program& program) {
2233     auto info = std::make_unique<UniformInfo>();
2234     for (const ProgramElement* e : program.elements()) {
2235         if (!e->is<GlobalVarDeclaration>()) {
2236             continue;
2237         }
2238         const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
2239         const Variable& var = decl.declaration()->as<VarDeclaration>().var();
2240         if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
2241             gather_uniforms(info.get(), var.type(), std::string(var.name()));
2242         }
2243     }
2244     return info;
2245 }
2246 
2247 /*
2248  * Testing utility function that emits program's "main" with a minimal harness. Used to create
2249  * representative skvm op sequences for SkSL tests.
2250  */
testingOnly_ProgramToSkVMShader(const Program & program,skvm::Builder * builder,SkVMDebugTrace * debugTrace)2251 bool testingOnly_ProgramToSkVMShader(const Program& program,
2252                                      skvm::Builder* builder,
2253                                      SkVMDebugTrace* debugTrace) {
2254     const SkSL::FunctionDefinition* main = Program_GetFunction(program, "main");
2255     if (!main) {
2256         return false;
2257     }
2258 
2259     size_t uniformSlots = 0;
2260     int childSlots = 0;
2261     for (const SkSL::ProgramElement* e : program.elements()) {
2262         if (e->is<GlobalVarDeclaration>()) {
2263             const GlobalVarDeclaration& decl = e->as<GlobalVarDeclaration>();
2264             const Variable& var = decl.declaration()->as<VarDeclaration>().var();
2265             if (var.type().isEffectChild()) {
2266                 childSlots++;
2267             } else if (is_uniform(var)) {
2268                 uniformSlots += var.type().slotCount();
2269             }
2270         }
2271     }
2272 
2273     skvm::Uniforms uniforms(builder->uniform(), 0);
2274 
2275     auto new_uni = [&]() { return builder->uniformF(uniforms.pushF(0.0f)); };
2276 
2277     // Assume identity CTM
2278     skvm::Coord device = {pun_to_F32(builder->index()), new_uni()};
2279     skvm::Coord local  = device;
2280 
2281     class Callbacks : public SkVMCallbacks {
2282     public:
2283         Callbacks(skvm::Builder* builder, skvm::Uniforms* uniforms, int numChildren) {
2284             for (int i = 0; i < numChildren; ++i) {
2285                 fChildren.push_back(
2286                         {uniforms->pushPtr(nullptr), builder->uniform32(uniforms->push(0))});
2287             }
2288         }
2289 
2290         skvm::Color sampleShader(int i, skvm::Coord coord) override {
2291             skvm::PixelFormat pixelFormat = skvm::SkColorType_to_PixelFormat(kRGBA_F32_SkColorType);
2292             skvm::I32 index  = trunc(coord.x);
2293                       index += trunc(coord.y) * fChildren[i].rowBytesAsPixels;
2294             return gather(pixelFormat, fChildren[i].addr, index);
2295         }
2296 
2297         skvm::Color sampleColorFilter(int i, skvm::Color color) override {
2298             return color;
2299         }
2300 
2301         skvm::Color sampleBlender(int i, skvm::Color src, skvm::Color dst) override {
2302             return blend(SkBlendMode::kSrcOver, src, dst);
2303         }
2304 
2305         // TODO(skia:10479): Make these actually convert to/from something like sRGB, for use in
2306         // test files.
2307         skvm::Color toLinearSrgb(skvm::Color color) override {
2308             return color;
2309         }
2310         skvm::Color fromLinearSrgb(skvm::Color color) override {
2311             return color;
2312         }
2313 
2314         struct Child {
2315             skvm::Uniform addr;
2316             skvm::I32     rowBytesAsPixels;
2317         };
2318         std::vector<Child> fChildren;
2319     };
2320     Callbacks callbacks(builder, &uniforms, childSlots);
2321 
2322     std::vector<skvm::Val> uniformVals;
2323     for (size_t i = 0; i < uniformSlots; ++i) {
2324         uniformVals.push_back(new_uni().id);
2325     }
2326 
2327     skvm::Color inColor = builder->uniformColor(SkColors::kWhite, &uniforms);
2328     skvm::Color destColor = builder->uniformColor(SkColors::kBlack, &uniforms);
2329 
2330     skvm::Color result = SkSL::ProgramToSkVM(program, *main, builder, debugTrace,
2331                                              SkMakeSpan(uniformVals), device, local, inColor,
2332                                              destColor, &callbacks);
2333 
2334     storeF(builder->varying<float>(), result.r);
2335     storeF(builder->varying<float>(), result.g);
2336     storeF(builder->varying<float>(), result.b);
2337     storeF(builder->varying<float>(), result.a);
2338 
2339     return true;
2340 }
2341 
2342 }  // namespace SkSL
2343