1 /* 2 * Copyright 2019 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 #ifndef SkVM_DEFINED 9 #define SkVM_DEFINED 10 11 #include "include/core/SkBlendMode.h" 12 #include "include/core/SkColor.h" 13 #include "include/private/SkMacros.h" 14 #include "include/private/SkTHash.h" 15 #include "src/core/SkSpan.h" 16 #include "src/core/SkVM_fwd.h" 17 #include <vector> // std::vector 18 19 class SkWStream; 20 21 #if 0 22 #define SKVM_LLVM 23 #endif 24 25 namespace skvm { 26 27 class Assembler { 28 public: 29 explicit Assembler(void* buf); 30 31 size_t size() const; 32 33 // Order matters... GP64, Xmm, Ymm values match 4-bit register encoding for each. 34 enum GP64 { 35 rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, 36 r8 , r9 , r10, r11, r12, r13, r14, r15, 37 }; 38 enum Xmm { 39 xmm0, xmm1, xmm2 , xmm3 , xmm4 , xmm5 , xmm6 , xmm7 , 40 xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, 41 }; 42 enum Ymm { 43 ymm0, ymm1, ymm2 , ymm3 , ymm4 , ymm5 , ymm6 , ymm7 , 44 ymm8, ymm9, ymm10, ymm11, ymm12, ymm13, ymm14, ymm15, 45 }; 46 47 // X and V values match 5-bit encoding for each (nothing tricky). 48 enum X { 49 x0 , x1 , x2 , x3 , x4 , x5 , x6 , x7 , 50 x8 , x9 , x10, x11, x12, x13, x14, x15, 51 x16, x17, x18, x19, x20, x21, x22, x23, 52 x24, x25, x26, x27, x28, x29, x30, xzr, 53 }; 54 enum V { 55 v0 , v1 , v2 , v3 , v4 , v5 , v6 , v7 , 56 v8 , v9 , v10, v11, v12, v13, v14, v15, 57 v16, v17, v18, v19, v20, v21, v22, v23, 58 v24, v25, v26, v27, v28, v29, v30, v31, 59 }; 60 61 void bytes(const void*, int); 62 void byte(uint8_t); 63 void word(uint32_t); 64 65 // x86-64 66 67 void align(int mod); 68 69 void int3(); 70 void vzeroupper(); 71 void ret(); 72 73 void add(GP64, int imm); 74 void sub(GP64, int imm); 75 76 void movq(GP64 dst, GP64 src, int off); // dst = *(src+off) 77 78 struct Label { 79 int offset = 0; 80 enum { NotYetSet, ARMDisp19, X86Disp32 } kind = NotYetSet; 81 std::vector<int> references; 82 }; 83 84 struct YmmOrLabel { 85 Ymm ymm = ymm0; 86 Label* label = nullptr; 87 YmmOrLabelYmmOrLabel88 /*implicit*/ YmmOrLabel(Ymm y) : ymm (y) { SkASSERT(!label); } YmmOrLabelYmmOrLabel89 /*implicit*/ YmmOrLabel(Label* l) : label(l) { SkASSERT( label); } 90 }; 91 92 // All dst = x op y. 93 using DstEqXOpY = void(Ymm dst, Ymm x, Ymm y); 94 DstEqXOpY vpandn, 95 vpmulld, 96 vpsubw, vpmullw, 97 vdivps, 98 vfmadd132ps, vfmadd213ps, vfmadd231ps, 99 vfmsub132ps, vfmsub213ps, vfmsub231ps, 100 vfnmadd132ps, vfnmadd213ps, vfnmadd231ps, 101 vpackusdw, vpackuswb, 102 vpcmpeqd, vpcmpgtd; 103 104 using DstEqXOpYOrLabel = void(Ymm dst, Ymm x, YmmOrLabel y); 105 DstEqXOpYOrLabel vpand, vpor, vpxor, 106 vpaddd, vpsubd, 107 vaddps, vsubps, vmulps, vminps, vmaxps; 108 109 // Floating point comparisons are all the same instruction with varying imm. 110 void vcmpps(Ymm dst, Ymm x, Ymm y, int imm); vcmpeqps(Ymm dst,Ymm x,Ymm y)111 void vcmpeqps (Ymm dst, Ymm x, Ymm y) { this->vcmpps(dst,x,y,0); } vcmpltps(Ymm dst,Ymm x,Ymm y)112 void vcmpltps (Ymm dst, Ymm x, Ymm y) { this->vcmpps(dst,x,y,1); } vcmpleps(Ymm dst,Ymm x,Ymm y)113 void vcmpleps (Ymm dst, Ymm x, Ymm y) { this->vcmpps(dst,x,y,2); } vcmpneqps(Ymm dst,Ymm x,Ymm y)114 void vcmpneqps(Ymm dst, Ymm x, Ymm y) { this->vcmpps(dst,x,y,4); } 115 116 using DstEqXOpImm = void(Ymm dst, Ymm x, int imm); 117 DstEqXOpImm vpslld, vpsrld, vpsrad, 118 vpsrlw, 119 vpermq, 120 vroundps; 121 122 enum { NEAREST, FLOOR, CEIL, TRUNC }; // vroundps immediates 123 124 using DstEqOpX = void(Ymm dst, Ymm x); 125 DstEqOpX vmovdqa, vcvtdq2ps, vcvttps2dq, vcvtps2dq, vsqrtps; 126 127 void vpblendvb(Ymm dst, Ymm x, Ymm y, Ymm z); 128 129 Label here(); 130 void label(Label*); 131 132 void jmp(Label*); 133 void je (Label*); 134 void jne(Label*); 135 void jl (Label*); 136 void jc (Label*); 137 void cmp(GP64, int imm); 138 139 void vpshufb(Ymm dst, Ymm x, Label*); 140 void vptest(Ymm dst, Label*); 141 142 void vbroadcastss(Ymm dst, Label*); 143 void vbroadcastss(Ymm dst, Xmm src); 144 void vbroadcastss(Ymm dst, GP64 ptr, int off); // dst = *(ptr+off) 145 146 void vmovups (Ymm dst, GP64 ptr); // dst = *ptr, 256-bit 147 void vpmovzxwd(Ymm dst, GP64 ptr); // dst = *ptr, 128-bit, each uint16_t expanded to int 148 void vpmovzxbd(Ymm dst, GP64 ptr); // dst = *ptr, 64-bit, each uint8_t expanded to int 149 void vmovd (Xmm dst, GP64 ptr); // dst = *ptr, 32-bit 150 151 enum Scale { ONE, TWO, FOUR, EIGHT }; 152 void vmovd(Xmm dst, Scale, GP64 index, GP64 base); // dst = *(base + scale*index), 32-bit 153 154 void vmovups(GP64 ptr, Ymm src); // *ptr = src, 256-bit 155 void vmovups(GP64 ptr, Xmm src); // *ptr = src, 128-bit 156 void vmovq (GP64 ptr, Xmm src); // *ptr = src, 64-bit 157 void vmovd (GP64 ptr, Xmm src); // *ptr = src, 32-bit 158 159 void movzbl(GP64 dst, GP64 ptr, int off); // dst = *(ptr+off), uint8_t -> int 160 void movb (GP64 ptr, GP64 src); // *ptr = src, 8-bit 161 162 void vmovd_direct(GP64 dst, Xmm src); // dst = src, 32-bit 163 void vmovd_direct(Xmm dst, GP64 src); // dst = src, 32-bit 164 165 void vpinsrw(Xmm dst, Xmm src, GP64 ptr, int imm); // dst = src; dst[imm] = *ptr, 16-bit 166 void vpinsrb(Xmm dst, Xmm src, GP64 ptr, int imm); // dst = src; dst[imm] = *ptr, 8-bit 167 168 void vpextrw(GP64 ptr, Xmm src, int imm); // *dst = src[imm] , 16-bit 169 void vpextrb(GP64 ptr, Xmm src, int imm); // *dst = src[imm] , 8-bit 170 171 // if (mask & 0x8000'0000) { 172 // dst = base[scale*ix]; 173 // } 174 // mask = 0; 175 void vgatherdps(Ymm dst, Scale scale, Ymm ix, GP64 base, Ymm mask); 176 177 // aarch64 178 179 // d = op(n,m) 180 using DOpNM = void(V d, V n, V m); 181 DOpNM and16b, orr16b, eor16b, bic16b, bsl16b, 182 add4s, sub4s, mul4s, 183 cmeq4s, cmgt4s, 184 sub8h, mul8h, 185 fadd4s, fsub4s, fmul4s, fdiv4s, fmin4s, fmax4s, 186 fcmeq4s, fcmgt4s, fcmge4s, 187 tbl; 188 189 // TODO: there are also float ==,<,<=,>,>= instructions with an immediate 0.0f, 190 // and the register comparison > and >= can also compare absolute values. Interesting. 191 192 // d += n*m 193 void fmla4s(V d, V n, V m); 194 195 // d -= n*m 196 void fmls4s(V d, V n, V m); 197 198 // d = op(n,imm) 199 using DOpNImm = void(V d, V n, int imm); 200 DOpNImm sli4s, 201 shl4s, sshr4s, ushr4s, 202 ushr8h; 203 204 // d = op(n) 205 using DOpN = void(V d, V n); 206 DOpN not16b, // d = ~n 207 fneg4s, // d = -n 208 scvtf4s, // int -> float 209 fcvtzs4s, // truncate float -> int 210 fcvtns4s, // round float -> int (nearest even) 211 xtns2h, // u32 -> u16 212 xtnh2b, // u16 -> u8 213 uxtlb2h, // u8 -> u16 214 uxtlh2s, // u16 -> u32 215 uminv4s; // dst[0] = min(n[0],n[1],n[2],n[3]), n as unsigned 216 217 void brk (int imm16); 218 void ret (X); 219 void add (X d, X n, int imm12); 220 void sub (X d, X n, int imm12); 221 void subs(X d, X n, int imm12); // subtract setting condition flags 222 223 // There's another encoding for unconditional branches that can jump further, 224 // but this one encoded as b.al is simple to implement and should be fine. b(Label * l)225 void b (Label* l) { this->b(Condition::al, l); } bne(Label * l)226 void bne(Label* l) { this->b(Condition::ne, l); } blt(Label * l)227 void blt(Label* l) { this->b(Condition::lt, l); } 228 229 // "cmp ..." is just an assembler mnemonic for "subs xzr, ..."! cmp(X n,int imm12)230 void cmp(X n, int imm12) { this->subs(xzr, n, imm12); } 231 232 // Compare and branch if zero/non-zero, as if 233 // cmp(t,0) 234 // beq/bne(l) 235 // but without setting condition flags. 236 void cbz (X t, Label* l); 237 void cbnz(X t, Label* l); 238 239 void ldrq(V dst, Label*); // 128-bit PC-relative load 240 241 void ldrq(V dst, X src); // 128-bit dst = *src 242 void ldrs(V dst, X src); // 32-bit dst = *src 243 void ldrb(V dst, X src); // 8-bit dst = *src 244 245 void strq(V src, X dst); // 128-bit *dst = src 246 void strs(V src, X dst); // 32-bit *dst = src 247 void strb(V src, X dst); // 8-bit *dst = src 248 249 void fmovs(X dst, V src); // dst = 32-bit src[0] 250 251 private: 252 // dst = op(dst, imm) 253 void op(int opcode, int opcode_ext, GP64 dst, int imm); 254 255 256 // dst = op(x,y) or op(x) 257 void op(int prefix, int map, int opcode, Ymm dst, Ymm x, Ymm y, bool W=false); 258 void op(int prefix, int map, int opcode, Ymm dst, Ymm x, bool W=false) { 259 // Two arguments ops seem to pass them in dst and y, forcing x to 0 so VEX.vvvv == 1111. 260 this->op(prefix, map, opcode, dst,(Ymm)0,x, W); 261 } 262 263 // dst = op(x,imm) 264 void op(int prefix, int map, int opcode, int opcode_ext, Ymm dst, Ymm x, int imm); 265 266 // dst = op(x,label) or op(label) 267 void op(int prefix, int map, int opcode, Ymm dst, Ymm x, Label* l); 268 void op(int prefix, int map, int opcode, Ymm dst, Ymm x, YmmOrLabel); 269 270 // *ptr = ymm or ymm = *ptr, depending on opcode. 271 void load_store(int prefix, int map, int opcode, Ymm ymm, GP64 ptr); 272 273 // Opcode for 3-arguments ops is split between hi and lo: 274 // [11 bits hi] [5 bits m] [6 bits lo] [5 bits n] [5 bits d] 275 void op(uint32_t hi, V m, uint32_t lo, V n, V d); 276 277 // 2-argument ops, with or without an immediate. 278 void op(uint32_t op22, int imm, V n, V d); op(uint32_t op22,V n,V d)279 void op(uint32_t op22, V n, V d) { this->op(op22,0,n,d); } op(uint32_t op22,X x,V v)280 void op(uint32_t op22, X x, V v) { this->op(op22,0,(V)x,v); } 281 282 // Order matters... value is 4-bit encoding for condition code. 283 enum class Condition { eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,al }; 284 void b(Condition, Label*); 285 286 void jump(uint8_t condition, Label*); 287 288 int disp19(Label*); 289 int disp32(Label*); 290 291 uint8_t* fCode; 292 uint8_t* fCurr; 293 size_t fSize; 294 }; 295 296 // Order matters a little: Ops <=store32 are treated as having side effects. 297 #define SKVM_OPS(M) \ 298 M(assert_true) \ 299 M(store8) M(store16) M(store32) \ 300 M(index) \ 301 M(load8) M(load16) M(load32) \ 302 M(gather8) M(gather16) M(gather32) \ 303 M(uniform8) M(uniform16) M(uniform32) \ 304 M(splat) \ 305 M(add_f32) M(add_i32) M(add_i16x2) \ 306 M(sub_f32) M(sub_i32) M(sub_i16x2) \ 307 M(mul_f32) M(mul_i32) M(mul_i16x2) \ 308 M(div_f32) \ 309 M(min_f32) \ 310 M(max_f32) \ 311 M(fma_f32) M(fms_f32) M(fnma_f32) \ 312 M(sqrt_f32) \ 313 M(shl_i32) M(shl_i16x2) \ 314 M(shr_i32) M(shr_i16x2) \ 315 M(sra_i32) M(sra_i16x2) \ 316 M(add_f32_imm) \ 317 M(sub_f32_imm) \ 318 M(mul_f32_imm) \ 319 M(min_f32_imm) \ 320 M(max_f32_imm) \ 321 M(floor) M(trunc) M(round) M(to_f32) \ 322 M( eq_f32) M( eq_i32) M( eq_i16x2) \ 323 M(neq_f32) M(neq_i32) M(neq_i16x2) \ 324 M( gt_f32) M( gt_i32) M( gt_i16x2) \ 325 M(gte_f32) M(gte_i32) M(gte_i16x2) \ 326 M(bit_and) \ 327 M(bit_or) \ 328 M(bit_xor) \ 329 M(bit_clear) \ 330 M(bit_and_imm) \ 331 M(bit_or_imm) \ 332 M(bit_xor_imm) \ 333 M(select) M(bytes) M(pack) \ 334 // End of SKVM_OPS 335 336 enum class Op : int { 337 #define M(op) op, 338 SKVM_OPS(M) 339 #undef M 340 }; 341 342 using Val = int; 343 // We reserve an impossibe Val ID as a sentinel 344 // NA meaning none, n/a, null, nil, etc. 345 static const Val NA = -1; 346 347 struct Arg { int ix; }; 348 349 struct I32 { 350 Builder* builder = nullptr; 351 Val id = NA; 352 explicit operator bool() const { return id != NA; } 353 Builder* operator->() const { return builder; } 354 }; 355 356 struct F32 { 357 Builder* builder = nullptr; 358 Val id = NA; 359 explicit operator bool() const { return id != NA; } 360 Builder* operator->() const { return builder; } 361 }; 362 363 // Some operations make sense with immediate arguments, 364 // so we use I32a and F32a to receive them transparently. 365 // 366 // We omit overloads that may indicate a bug or performance issue. 367 // In general it does not make sense to pass immediates to unary operations, 368 // and even sometimes not for binary operations, e.g. 369 // 370 // div(x,y) -- normal every day divide 371 // div(3.0f,y) -- yep, makes sense 372 // div(x,3.0f) -- omitted as a reminder you probably want mul(x, 1/3.0f). 373 // 374 // You can of course always splat() to override these opinions. 375 struct I32a { I32aI32a376 I32a(I32 v) : SkDEBUGCODE(builder(v.builder),) id(v.id) {} I32aI32a377 I32a(int v) : imm(v) {} 378 379 SkDEBUGCODE(Builder* builder = nullptr;) 380 Val id = NA; 381 int imm = 0; 382 }; 383 384 struct F32a { F32aF32a385 F32a(F32 v) : SkDEBUGCODE(builder(v.builder),) id(v.id) {} F32aF32a386 F32a(float v) : imm(v) {} 387 388 SkDEBUGCODE(Builder* builder = nullptr;) 389 Val id = NA; 390 float imm = 0; 391 }; 392 393 struct Color { 394 skvm::F32 r,g,b,a; 395 explicit operator bool() const { return r && g && b && a; } 396 Builder* operator->() const { return a.operator->(); } 397 }; 398 399 struct HSLA { 400 skvm::F32 h,s,l,a; 401 explicit operator bool() const { return h && s && l && a; } 402 Builder* operator->() const { return a.operator->(); } 403 }; 404 405 struct Uniform { 406 Arg ptr; 407 int offset; 408 }; 409 struct Uniforms { 410 Arg base; 411 std::vector<int> buf; 412 UniformsUniforms413 explicit Uniforms(int init) : base(Arg{0}), buf(init) {} 414 pushUniforms415 Uniform push(int val) { 416 buf.push_back(val); 417 return {base, (int)( sizeof(int)*(buf.size() - 1) )}; 418 } 419 pushFUniforms420 Uniform pushF(float val) { 421 int bits; 422 memcpy(&bits, &val, sizeof(int)); 423 return this->push(bits); 424 } 425 pushPtrUniforms426 Uniform pushPtr(const void* ptr) { 427 // Jam the pointer into 1 or 2 ints. 428 int ints[sizeof(ptr) / sizeof(int)]; 429 memcpy(ints, &ptr, sizeof(ptr)); 430 for (int bits : ints) { 431 buf.push_back(bits); 432 } 433 return {base, (int)( sizeof(int)*(buf.size() - SK_ARRAY_COUNT(ints)) )}; 434 } 435 }; 436 437 SK_BEGIN_REQUIRE_DENSE 438 struct Instruction { 439 Op op; // v* = op(x,y,z,imm), where * == index of this Instruction. 440 Val x,y,z; // Enough arguments for mad(). 441 int immy,immz; // Immediate bit pattern, shift count, argument index, etc. 442 }; 443 SK_END_REQUIRE_DENSE 444 445 bool operator==(const Instruction&, const Instruction&); 446 struct InstructionHash { 447 uint32_t operator()(const Instruction&, uint32_t seed=0) const; 448 }; 449 450 struct OptimizedInstruction { 451 Op op; 452 Val x,y,z; 453 int immy,immz; 454 455 Val death; 456 bool can_hoist; 457 bool used_in_loop; 458 }; 459 460 class Builder { 461 public: 462 463 Program done(const char* debug_name = nullptr) const; 464 465 // Mostly for debugging, tests, etc. program()466 std::vector<Instruction> program() const { return fProgram; } 467 std::vector<OptimizedInstruction> optimize(bool for_jit=false) const; 468 469 // Declare an argument with given stride (use stride=0 for uniforms). 470 // TODO: different types for varying and uniforms? 471 Arg arg(int stride); 472 473 // Convenience arg() wrappers for most common strides, sizeof(T) and 0. 474 template <typename T> varying()475 Arg varying() { return this->arg(sizeof(T)); } uniform()476 Arg uniform() { return this->arg(0); } 477 478 // TODO: allow uniform (i.e. Arg) offsets to store* and load*? 479 // TODO: sign extension (signed types) for <32-bit loads? 480 // TODO: unsigned integer operations where relevant (just comparisons?)? 481 482 // Assert cond is true, printing debug when not. 483 void assert_true(I32 cond, I32 debug); assert_true(I32 cond,F32 debug)484 void assert_true(I32 cond, F32 debug) { assert_true(cond, bit_cast(debug)); } assert_true(I32 cond)485 void assert_true(I32 cond) { assert_true(cond, cond); } 486 487 // Store {8,16,32}-bit varying. 488 void store8 (Arg ptr, I32 val); 489 void store16(Arg ptr, I32 val); 490 void store32(Arg ptr, I32 val); storeF(Arg ptr,F32 val)491 void storeF (Arg ptr, F32 val) { store32(ptr, bit_cast(val)); } 492 493 // Returns varying {n, n-1, n-2, ..., 1}, where n is the argument to Program::eval(). 494 I32 index(); 495 496 // Load u8,u16,i32 varying. 497 I32 load8 (Arg ptr); 498 I32 load16(Arg ptr); 499 I32 load32(Arg ptr); loadF(Arg ptr)500 F32 loadF (Arg ptr) { return bit_cast(load32(ptr)); } 501 502 // Load u8,u16,i32 uniform with byte-count offset. 503 I32 uniform8 (Arg ptr, int offset); 504 I32 uniform16(Arg ptr, int offset); 505 I32 uniform32(Arg ptr, int offset); uniformF(Arg ptr,int offset)506 F32 uniformF (Arg ptr, int offset) { return this->bit_cast(this->uniform32(ptr,offset)); } 507 508 // Load this color as a uniform, premultiplied and converted to dst SkColorSpace. 509 Color uniformPremul(SkColor4f, SkColorSpace* src, 510 Uniforms*, SkColorSpace* dst); 511 512 // Gather u8,u16,i32 with varying element-count index from *(ptr + byte-count offset). 513 I32 gather8 (Arg ptr, int offset, I32 index); 514 I32 gather16(Arg ptr, int offset, I32 index); 515 I32 gather32(Arg ptr, int offset, I32 index); gatherF(Arg ptr,int offset,I32 index)516 F32 gatherF (Arg ptr, int offset, I32 index) { 517 return bit_cast(gather32(ptr, offset, index)); 518 } 519 520 // Convenience methods for working with skvm::Uniform(s). uniform8(Uniform u)521 I32 uniform8 (Uniform u) { return this->uniform8 (u.ptr, u.offset); } uniform16(Uniform u)522 I32 uniform16(Uniform u) { return this->uniform16(u.ptr, u.offset); } uniform32(Uniform u)523 I32 uniform32(Uniform u) { return this->uniform32(u.ptr, u.offset); } uniformF(Uniform u)524 F32 uniformF (Uniform u) { return this->uniformF (u.ptr, u.offset); } gather8(Uniform u,I32 index)525 I32 gather8 (Uniform u, I32 index) { return this->gather8 (u.ptr, u.offset, index); } gather16(Uniform u,I32 index)526 I32 gather16 (Uniform u, I32 index) { return this->gather16 (u.ptr, u.offset, index); } gather32(Uniform u,I32 index)527 I32 gather32 (Uniform u, I32 index) { return this->gather32 (u.ptr, u.offset, index); } gatherF(Uniform u,I32 index)528 F32 gatherF (Uniform u, I32 index) { return this->gatherF (u.ptr, u.offset, index); } 529 530 // Load an immediate constant. 531 I32 splat(int n); splat(unsigned u)532 I32 splat(unsigned u) { return this->splat((int)u); } 533 F32 splat(float f); 534 535 // float math, comparisons, etc. add(F32a x,F32a y)536 F32 add(F32, F32); F32 add(F32a x, F32a y) { return add(_(x), _(y)); } sub(F32a x,F32a y)537 F32 sub(F32, F32); F32 sub(F32a x, F32a y) { return sub(_(x), _(y)); } mul(F32a x,F32a y)538 F32 mul(F32, F32); F32 mul(F32a x, F32a y) { return mul(_(x), _(y)); } div(F32a x,F32 y)539 F32 div(F32, F32); F32 div(F32a x, F32 y) { return div(_(x), y ); } min(F32a x,F32a y)540 F32 min(F32, F32); F32 min(F32a x, F32a y) { return min(_(x), _(y)); } max(F32a x,F32a y)541 F32 max(F32, F32); F32 max(F32a x, F32a y) { return max(_(x), _(y)); } 542 mad(F32 x,F32 y,F32 z)543 F32 mad(F32 x, F32 y, F32 z) { return add(mul(x,y), z); } mad(F32a x,F32a y,F32a z)544 F32 mad(F32a x, F32a y, F32a z) { return mad(_(x), _(y), _(z)); } 545 546 F32 sqrt(F32); 547 F32 approx_log2(F32); 548 F32 approx_pow2(F32); approx_log(F32 x)549 F32 approx_log (F32 x) { return mul(0.69314718f, approx_log2(x)); } approx_exp(F32 x)550 F32 approx_exp (F32 x) { return approx_pow2(mul(x, 1.4426950408889634074f)); } 551 552 F32 approx_powf(F32 base, F32 exp); approx_powf(F32a base,F32a exp)553 F32 approx_powf(F32a base, F32a exp) { return approx_powf(_(base), _(exp)); } 554 lerp(F32 lo,F32 hi,F32 t)555 F32 lerp(F32 lo, F32 hi, F32 t) { return mad(sub(hi, lo), t, lo); } lerp(F32a lo,F32a hi,F32a t)556 F32 lerp(F32a lo, F32a hi, F32a t) { return lerp(_(lo), _(hi), _(t)); } 557 clamp(F32 x,F32 lo,F32 hi)558 F32 clamp(F32 x, F32 lo, F32 hi) { return max(lo, min(x, hi)); } clamp(F32a x,F32a lo,F32a hi)559 F32 clamp(F32a x, F32a lo, F32a hi) { return clamp(_(x), _(lo), _(hi)); } clamp01(F32 x)560 F32 clamp01(F32 x) { return clamp(x, 0.0f, 1.0f); } 561 abs(F32 x)562 F32 abs(F32 x) { return bit_cast(bit_and(bit_cast(x), 0x7fff'ffff)); } 563 F32 fract(F32 x) { return sub(x, floor(x)); } 564 F32 floor(F32); 565 566 I32 trunc(F32 x); 567 I32 round(F32 x); // Round to int using current rounding mode (as if lrintf()). 568 I32 bit_cast(F32 x) { return {x.builder, x.id}; } 569 570 F32 norm(F32 x, F32 y) { 571 return sqrt(add(mul(x,x), 572 mul(y,y))); 573 } 574 F32 norm(F32a x, F32a y) { return norm(_(x), _(y)); } 575 576 I32 eq(F32, F32); I32 eq(F32a x, F32a y) { return eq(_(x), _(y)); } 577 I32 neq(F32, F32); I32 neq(F32a x, F32a y) { return neq(_(x), _(y)); } 578 I32 lt (F32, F32); I32 lt (F32a x, F32a y) { return lt (_(x), _(y)); } 579 I32 lte(F32, F32); I32 lte(F32a x, F32a y) { return lte(_(x), _(y)); } 580 I32 gt (F32, F32); I32 gt (F32a x, F32a y) { return gt (_(x), _(y)); } 581 I32 gte(F32, F32); I32 gte(F32a x, F32a y) { return gte(_(x), _(y)); } 582 583 // int math, comparisons, etc. 584 I32 add(I32, I32); I32 add(I32a x, I32a y) { return add(_(x), _(y)); } 585 I32 sub(I32, I32); I32 sub(I32a x, I32a y) { return sub(_(x), _(y)); } 586 I32 mul(I32, I32); I32 mul(I32a x, I32a y) { return mul(_(x), _(y)); } 587 588 I32 shl(I32 x, int bits); 589 I32 shr(I32 x, int bits); 590 I32 sra(I32 x, int bits); 591 592 I32 eq (I32 x, I32 y); I32 eq(I32a x, I32a y) { return eq(_(x), _(y)); } 593 I32 neq(I32 x, I32 y); I32 neq(I32a x, I32a y) { return neq(_(x), _(y)); } 594 I32 lt (I32 x, I32 y); I32 lt (I32a x, I32a y) { return lt (_(x), _(y)); } 595 I32 lte(I32 x, I32 y); I32 lte(I32a x, I32a y) { return lte(_(x), _(y)); } 596 I32 gt (I32 x, I32 y); I32 gt (I32a x, I32a y) { return gt (_(x), _(y)); } 597 I32 gte(I32 x, I32 y); I32 gte(I32a x, I32a y) { return gte(_(x), _(y)); } 598 599 F32 to_f32(I32 x); 600 F32 bit_cast(I32 x) { return {x.builder, x.id}; } 601 602 // Treat each 32-bit lane as a pair of 16-bit ints. 603 I32 add_16x2(I32, I32); I32 add_16x2(I32a x, I32a y) { return add_16x2(_(x), _(y)); } 604 I32 sub_16x2(I32, I32); I32 sub_16x2(I32a x, I32a y) { return sub_16x2(_(x), _(y)); } 605 I32 mul_16x2(I32, I32); I32 mul_16x2(I32a x, I32a y) { return mul_16x2(_(x), _(y)); } 606 607 I32 shl_16x2(I32 x, int bits); 608 I32 shr_16x2(I32 x, int bits); 609 I32 sra_16x2(I32 x, int bits); 610 611 I32 eq_16x2(I32, I32); I32 eq_16x2(I32a x, I32a y) { return eq_16x2(_(x), _(y)); } 612 I32 neq_16x2(I32, I32); I32 neq_16x2(I32a x, I32a y) { return neq_16x2(_(x), _(y)); } 613 I32 lt_16x2(I32, I32); I32 lt_16x2(I32a x, I32a y) { return lt_16x2(_(x), _(y)); } 614 I32 lte_16x2(I32, I32); I32 lte_16x2(I32a x, I32a y) { return lte_16x2(_(x), _(y)); } 615 I32 gt_16x2(I32, I32); I32 gt_16x2(I32a x, I32a y) { return gt_16x2(_(x), _(y)); } 616 I32 gte_16x2(I32, I32); I32 gte_16x2(I32a x, I32a y) { return gte_16x2(_(x), _(y)); } 617 618 // Bitwise operations. 619 I32 bit_and (I32, I32); I32 bit_and (I32a x, I32a y) { return bit_and (_(x), _(y)); } 620 I32 bit_or (I32, I32); I32 bit_or (I32a x, I32a y) { return bit_or (_(x), _(y)); } 621 I32 bit_xor (I32, I32); I32 bit_xor (I32a x, I32a y) { return bit_xor (_(x), _(y)); } 622 I32 bit_clear(I32, I32); I32 bit_clear(I32a x, I32a y) { return bit_clear(_(x), _(y)); } 623 624 I32 min(I32 x, I32 y) { return select(lt(x,y), x, y); } 625 I32 max(I32 x, I32 y) { return select(gt(x,y), x, y); } 626 627 I32 min(I32a x, I32a y) { return min(_(x), _(y)); } 628 I32 max(I32a x, I32a y) { return max(_(x), _(y)); } 629 630 I32 select(I32 cond, I32 t, I32 f); // cond ? t : f 631 F32 select(I32 cond, F32 t, F32 f) { 632 return this->bit_cast(this->select(cond, this->bit_cast(t) 633 , this->bit_cast(f))); 634 } 635 636 I32 select(I32a cond, I32a t, I32a f) { return select(_(cond), _(t), _(f)); } 637 F32 select(I32a cond, F32a t, F32a f) { return select(_(cond), _(t), _(f)); } 638 639 // More complex operations... 640 641 // Shuffle the bytes in x according to each nibble of control, as if 642 // 643 // uint8_t bytes[] = { 644 // 0, 645 // ((uint32_t)x ) & 0xff, 646 // ((uint32_t)x >> 8) & 0xff, 647 // ((uint32_t)x >> 16) & 0xff, 648 // ((uint32_t)x >> 24) & 0xff, 649 // }; 650 // return (uint32_t)bytes[(control >> 0) & 0xf] << 0 651 // | (uint32_t)bytes[(control >> 4) & 0xf] << 8 652 // | (uint32_t)bytes[(control >> 8) & 0xf] << 16 653 // | (uint32_t)bytes[(control >> 12) & 0xf] << 24; 654 // 655 // So, e.g., 656 // - bytes(x, 0x1111) splats the low byte of x to all four bytes 657 // - bytes(x, 0x4321) is x, an identity 658 // - bytes(x, 0x0000) is 0 659 // - bytes(x, 0x0404) transforms an RGBA pixel into an A0A0 bit pattern. 660 I32 bytes (I32 x, int control); 661 662 I32 extract(I32 x, int bits, I32 z); // (x>>bits) & z 663 I32 pack (I32 x, I32 y, int bits); // x | (y << bits), assuming (x & (y << bits)) == 0 664 665 I32 extract(I32a x, int bits, I32a z) { return extract(_(x), bits, _(z)); } 666 I32 pack (I32a x, I32a y, int bits) { return pack (_(x), _(y), bits); } 667 668 669 // Common idioms used in several places, worth centralizing for consistency. 670 F32 from_unorm(int bits, I32); // E.g. from_unorm(8, x) -> x * (1/255.0f) 671 I32 to_unorm(int bits, F32); // E.g. to_unorm(8, x) -> round(x * 255) 672 673 Color unpack_1010102(I32 rgba); 674 Color unpack_8888 (I32 rgba); 675 Color unpack_565 (I32 bgr ); // bottom 16 bits 676 677 void premul(F32* r, F32* g, F32* b, F32 a); 678 void unpremul(F32* r, F32* g, F32* b, F32 a); 679 680 Color premul(Color c) { this->premul(&c.r, &c.g, &c.b, c.a); return c; } 681 Color unpremul(Color c) { this->unpremul(&c.r, &c.g, &c.b, c.a); return c; } 682 Color lerp(Color lo, Color hi, F32 t); 683 Color blend(SkBlendMode, Color src, Color dst); 684 685 HSLA to_hsla(Color); 686 Color to_rgba(HSLA); 687 688 void dump(SkWStream* = nullptr) const; 689 void dot (SkWStream* = nullptr, bool for_jit=false) const; 690 691 uint64_t hash() const; 692 693 Val push(Instruction); 694 private: 695 Val push(Op op, Val x, Val y=NA, Val z=NA, int immy=0, int immz=0) { 696 return this->push(Instruction{op, x,y,z, immy,immz}); 697 } 698 699 I32 _(I32a x) { 700 if (x.id != NA) { 701 SkASSERT(x.builder == this); 702 return {this, x.id}; 703 } 704 return this->splat(x.imm); 705 } 706 707 F32 _(F32a x) { 708 if (x.id != NA) { 709 SkASSERT(x.builder == this); 710 return {this, x.id}; 711 } 712 return this->splat(x.imm); 713 } 714 715 bool allImm() const; 716 717 template <typename T, typename... Rest> 718 bool allImm(Val, T* imm, Rest...) const; 719 720 template <typename T> 721 bool isImm(Val id, T want) const { 722 T imm = 0; 723 return this->allImm(id, &imm) && imm == want; 724 } 725 726 SkTHashMap<Instruction, Val, InstructionHash> fIndex; 727 std::vector<Instruction> fProgram; 728 std::vector<int> fStrides; 729 }; 730 731 // Optimization passes and data structures normally used by Builder::optimize(), 732 // extracted here so they can be unit tested. 733 734 void specialize_for_jit(std::vector<Instruction>* program); 735 736 // Fill live and sinks each if non-null: 737 // - (*live)[id]: notes whether each input instruction is live 738 // - *sinks: an unsorted set of live instructions with side effects (stores, assert_true) 739 // Returns the number of live instructions. 740 int liveness_analysis(const std::vector<Instruction>&, 741 std::vector<bool>* live, 742 std::vector<Val>* sinks); 743 744 class Usage { 745 public: 746 Usage(const std::vector<Instruction>&, const std::vector<bool>&); 747 748 // Return a sorted span of Vals which use result of Instruction id. 749 SkSpan<const Val> users(Val id) const; 750 751 private: 752 std::vector<int> fIndex; 753 std::vector<Val> fTable; 754 }; 755 756 using Reg = int; 757 758 // d = op(x, y/imm, z/imm) 759 struct InterpreterInstruction { 760 Op op; 761 Reg d,x; 762 union { Reg y; int immy; }; 763 union { Reg z; int immz; }; 764 }; 765 766 class Program { 767 public: 768 Program(const std::vector<OptimizedInstruction>& interpreter, 769 const std::vector<int>& strides); 770 771 Program(const std::vector<OptimizedInstruction>& interpreter, 772 const std::vector<OptimizedInstruction>& jit, 773 const std::vector<int>& strides, 774 const char* debug_name); 775 776 Program(); 777 ~Program(); 778 779 Program(Program&&); 780 Program& operator=(Program&&); 781 782 Program(const Program&) = delete; 783 Program& operator=(const Program&) = delete; 784 785 void eval(int n, void* args[]) const; 786 787 template <typename... T> 788 void eval(int n, T*... arg) const { 789 SkASSERT(sizeof...(arg) == this->nargs()); 790 // This nullptr isn't important except that it makes args[] non-empty if you pass none. 791 void* args[] = { (void*)arg..., nullptr }; 792 this->eval(n, args); 793 } 794 795 std::vector<InterpreterInstruction> instructions() const; 796 int nargs() const; 797 int nregs() const; 798 int loop () const; 799 bool empty() const; 800 801 bool hasJIT() const; // Has this Program been JITted? 802 void dropJIT(); // If hasJIT(), drop it, forcing interpreter fallback. 803 804 void dump(SkWStream* = nullptr) const; 805 806 private: 807 void setupInterpreter(const std::vector<OptimizedInstruction>&); 808 void setupJIT (const std::vector<OptimizedInstruction>&, const char* debug_name); 809 void setupLLVM (const std::vector<OptimizedInstruction>&, const char* debug_name); 810 811 bool jit(const std::vector<OptimizedInstruction>&, 812 bool try_hoisting, 813 Assembler*) const; 814 815 void waitForLLVM() const; 816 817 struct Impl; 818 std::unique_ptr<Impl> fImpl; 819 }; 820 821 // TODO: control flow 822 // TODO: 64-bit values? 823 824 static inline I32 operator+(I32 x, I32a y) { return x->add(x,y); } 825 static inline I32 operator+(int x, I32 y) { return y->add(x,y); } 826 827 static inline I32 operator-(I32 x, I32a y) { return x->sub(x,y); } 828 static inline I32 operator-(int x, I32 y) { return y->sub(x,y); } 829 830 static inline I32 operator*(I32 x, I32a y) { return x->mul(x,y); } 831 static inline I32 operator*(int x, I32 y) { return y->mul(x,y); } 832 min(I32 x,I32a y)833 static inline I32 min(I32 x, I32a y) { return x->min(x,y); } min(int x,I32 y)834 static inline I32 min(int x, I32 y) { return y->min(x,y); } 835 max(I32 x,I32a y)836 static inline I32 max(I32 x, I32a y) { return x->max(x,y); } max(int x,I32 y)837 static inline I32 max(int x, I32 y) { return y->max(x,y); } 838 839 static inline I32 operator==(I32 x, I32a y) { return x->eq(x,y); } 840 static inline I32 operator==(int x, I32 y) { return y->eq(x,y); } 841 842 static inline I32 operator!=(I32 x, I32a y) { return x->neq(x,y); } 843 static inline I32 operator!=(int x, I32 y) { return y->neq(x,y); } 844 845 static inline I32 operator< (I32 x, I32a y) { return x->lt(x,y); } 846 static inline I32 operator< (int x, I32 y) { return y->lt(x,y); } 847 848 static inline I32 operator<=(I32 x, I32a y) { return x->lte(x,y); } 849 static inline I32 operator<=(int x, I32 y) { return y->lte(x,y); } 850 851 static inline I32 operator> (I32 x, I32a y) { return x->gt(x,y); } 852 static inline I32 operator> (int x, I32 y) { return y->gt(x,y); } 853 854 static inline I32 operator>=(I32 x, I32a y) { return x->gte(x,y); } 855 static inline I32 operator>=(int x, I32 y) { return y->gte(x,y); } 856 857 858 static inline F32 operator+(F32 x, F32a y) { return x->add(x,y); } 859 static inline F32 operator+(float x, F32 y) { return y->add(x,y); } 860 861 static inline F32 operator-(F32 x, F32a y) { return x->sub(x,y); } 862 static inline F32 operator-(float x, F32 y) { return y->sub(x,y); } 863 864 static inline F32 operator*(F32 x, F32a y) { return x->mul(x,y); } 865 static inline F32 operator*(float x, F32 y) { return y->mul(x,y); } 866 867 static inline F32 operator/(F32 x, F32 y) { return x->div(x,y); } 868 static inline F32 operator/(float x, F32 y) { return y->div(x,y); } 869 min(F32 x,F32a y)870 static inline F32 min(F32 x, F32a y) { return x->min(x,y); } min(float x,F32 y)871 static inline F32 min(float x, F32 y) { return y->min(x,y); } 872 max(F32 x,F32a y)873 static inline F32 max(F32 x, F32a y) { return x->max(x,y); } max(float x,F32 y)874 static inline F32 max(float x, F32 y) { return y->max(x,y); } 875 876 static inline I32 operator==(F32 x, F32a y) { return x->eq(x,y); } 877 static inline I32 operator==(float x, F32 y) { return y->eq(x,y); } 878 879 static inline I32 operator!=(F32 x, F32a y) { return x->neq(x,y); } 880 static inline I32 operator!=(float x, F32 y) { return y->neq(x,y); } 881 882 static inline I32 operator< (F32 x, F32a y) { return x->lt(x,y); } 883 static inline I32 operator< (float x, F32 y) { return y->lt(x,y); } 884 885 static inline I32 operator<=(F32 x, F32a y) { return x->lte(x,y); } 886 static inline I32 operator<=(float x, F32 y) { return y->lte(x,y); } 887 888 static inline I32 operator> (F32 x, F32a y) { return x->gt(x,y); } 889 static inline I32 operator> (float x, F32 y) { return y->gt(x,y); } 890 891 static inline I32 operator>=(F32 x, F32a y) { return x->gte(x,y); } 892 static inline I32 operator>=(float x, F32 y) { return y->gte(x,y); } 893 894 895 static inline I32& operator+=(I32& x, I32a y) { return (x = x + y); } 896 static inline I32& operator-=(I32& x, I32a y) { return (x = x - y); } 897 static inline I32& operator*=(I32& x, I32a y) { return (x = x * y); } 898 899 static inline F32& operator+=(F32& x, F32a y) { return (x = x + y); } 900 static inline F32& operator-=(F32& x, F32a y) { return (x = x - y); } 901 static inline F32& operator*=(F32& x, F32a y) { return (x = x * y); } 902 903 static inline I32 operator-(I32 x) { return 0-x; } 904 static inline F32 operator-(F32 x) { return 0-x; } 905 assert_true(I32 cond,I32 debug)906 static inline void assert_true(I32 cond, I32 debug) { cond->assert_true(cond,debug); } assert_true(I32 cond,F32 debug)907 static inline void assert_true(I32 cond, F32 debug) { cond->assert_true(cond,debug); } assert_true(I32 cond)908 static inline void assert_true(I32 cond) { cond->assert_true(cond); } 909 store8(Arg ptr,I32 val)910 static inline void store8 (Arg ptr, I32 val) { val->store8 (ptr, val); } store16(Arg ptr,I32 val)911 static inline void store16(Arg ptr, I32 val) { val->store16(ptr, val); } store32(Arg ptr,I32 val)912 static inline void store32(Arg ptr, I32 val) { val->store32(ptr, val); } storeF(Arg ptr,F32 val)913 static inline void storeF (Arg ptr, F32 val) { val->storeF (ptr, val); } 914 gather8(Arg ptr,int off,I32 ix)915 static inline I32 gather8 (Arg ptr, int off, I32 ix) { return ix->gather8 (ptr, off, ix); } gather16(Arg ptr,int off,I32 ix)916 static inline I32 gather16(Arg ptr, int off, I32 ix) { return ix->gather16(ptr, off, ix); } gather32(Arg ptr,int off,I32 ix)917 static inline I32 gather32(Arg ptr, int off, I32 ix) { return ix->gather32(ptr, off, ix); } gatherF(Arg ptr,int off,I32 ix)918 static inline F32 gatherF (Arg ptr, int off, I32 ix) { return ix->gatherF (ptr, off, ix); } 919 gather8(Uniform u,I32 ix)920 static inline I32 gather8 (Uniform u, I32 ix) { return ix->gather8 (u, ix); } gather16(Uniform u,I32 ix)921 static inline I32 gather16(Uniform u, I32 ix) { return ix->gather16(u, ix); } gather32(Uniform u,I32 ix)922 static inline I32 gather32(Uniform u, I32 ix) { return ix->gather32(u, ix); } gatherF(Uniform u,I32 ix)923 static inline F32 gatherF (Uniform u, I32 ix) { return ix->gatherF (u, ix); } 924 sqrt(F32 x)925 static inline F32 sqrt(F32 x) { return x-> sqrt(x); } approx_log2(F32 x)926 static inline F32 approx_log2(F32 x) { return x->approx_log2(x); } approx_pow2(F32 x)927 static inline F32 approx_pow2(F32 x) { return x->approx_pow2(x); } approx_log(F32 x)928 static inline F32 approx_log (F32 x) { return x->approx_log (x); } approx_exp(F32 x)929 static inline F32 approx_exp (F32 x) { return x->approx_exp (x); } 930 approx_powf(F32 base,F32a exp)931 static inline F32 approx_powf(F32 base, F32a exp) { return base->approx_powf(base, exp); } approx_powf(float base,F32 exp)932 static inline F32 approx_powf(float base, F32 exp) { return exp->approx_powf(base, exp); } 933 clamp01(F32 x)934 static inline F32 clamp01(F32 x) { return x->clamp01(x); } abs(F32 x)935 static inline F32 abs(F32 x) { return x-> abs(x); } fract(F32 x)936 static inline F32 fract(F32 x) { return x-> fract(x); } floor(F32 x)937 static inline F32 floor(F32 x) { return x-> floor(x); } 938 trunc(F32 x)939 static inline I32 trunc(F32 x) { return x-> trunc(x); } round(F32 x)940 static inline I32 round(F32 x) { return x-> round(x); } bit_cast(F32 x)941 static inline I32 bit_cast(F32 x) { return x->bit_cast(x); } bit_cast(I32 x)942 static inline F32 bit_cast(I32 x) { return x->bit_cast(x); } to_f32(I32 x)943 static inline F32 to_f32(I32 x) { return x-> to_f32(x); } 944 lerp(F32 lo,F32a hi,F32a t)945 static inline F32 lerp(F32 lo, F32a hi, F32a t) { return lo->lerp(lo,hi,t); } lerp(float lo,F32 hi,F32a t)946 static inline F32 lerp(float lo, F32 hi, F32a t) { return hi->lerp(lo,hi,t); } lerp(float lo,float hi,F32 t)947 static inline F32 lerp(float lo, float hi, F32 t) { return t->lerp(lo,hi,t); } 948 clamp(F32 x,F32a lo,F32a hi)949 static inline F32 clamp(F32 x, F32a lo, F32a hi) { return x->clamp(x,lo,hi); } clamp(float x,F32 lo,F32a hi)950 static inline F32 clamp(float x, F32 lo, F32a hi) { return lo->clamp(x,lo,hi); } clamp(float x,float lo,F32 hi)951 static inline F32 clamp(float x, float lo, F32 hi) { return hi->clamp(x,lo,hi); } 952 norm(F32 x,F32a y)953 static inline F32 norm(F32 x, F32a y) { return x->norm(x,y); } norm(float x,F32 y)954 static inline F32 norm(float x, F32 y) { return y->norm(x,y); } 955 956 static inline I32 operator<<(I32 x, int bits) { return x->shl(x, bits); } shl(I32 x,int bits)957 static inline I32 shl(I32 x, int bits) { return x->shl(x, bits); } shr(I32 x,int bits)958 static inline I32 shr(I32 x, int bits) { return x->shr(x, bits); } sra(I32 x,int bits)959 static inline I32 sra(I32 x, int bits) { return x->sra(x, bits); } 960 961 static inline I32 operator&(I32 x, I32a y) { return x->bit_and(x,y); } 962 static inline I32 operator&(int x, I32 y) { return y->bit_and(x,y); } 963 964 static inline I32 operator|(I32 x, I32a y) { return x->bit_or (x,y); } 965 static inline I32 operator|(int x, I32 y) { return y->bit_or (x,y); } 966 967 static inline I32 operator^(I32 x, I32a y) { return x->bit_xor(x,y); } 968 static inline I32 operator^(int x, I32 y) { return y->bit_xor(x,y); } 969 970 static inline I32& operator&=(I32& x, I32a y) { return (x = x & y); } 971 static inline I32& operator|=(I32& x, I32a y) { return (x = x | y); } 972 static inline I32& operator^=(I32& x, I32a y) { return (x = x ^ y); } 973 select(I32 cond,I32a t,I32a f)974 static inline I32 select(I32 cond, I32a t, I32a f) { return cond->select(cond,t,f); } select(I32 cond,F32a t,F32a f)975 static inline F32 select(I32 cond, F32a t, F32a f) { return cond->select(cond,t,f); } 976 bytes(I32 x,int control)977 static inline I32 bytes(I32 x, int control) { return x->bytes(x,control); } 978 extract(I32 x,int bits,I32a z)979 static inline I32 extract(I32 x, int bits, I32a z) { return x->extract(x,bits,z); } extract(int x,int bits,I32 z)980 static inline I32 extract(int x, int bits, I32 z) { return z->extract(x,bits,z); } pack(I32 x,I32a y,int bits)981 static inline I32 pack (I32 x, I32a y, int bits) { return x->pack (x,y,bits); } pack(int x,I32 y,int bits)982 static inline I32 pack (int x, I32 y, int bits) { return y->pack (x,y,bits); } 983 from_unorm(int bits,I32 x)984 static inline F32 from_unorm(int bits, I32 x) { return x->from_unorm(bits,x); } to_unorm(int bits,F32 x)985 static inline I32 to_unorm(int bits, F32 x) { return x-> to_unorm(bits,x); } 986 unpack_1010102(I32 rgba)987 static inline Color unpack_1010102(I32 rgba) { return rgba->unpack_1010102(rgba); } unpack_8888(I32 rgba)988 static inline Color unpack_8888 (I32 rgba) { return rgba->unpack_8888 (rgba); } unpack_565(I32 bgr)989 static inline Color unpack_565 (I32 bgr ) { return bgr ->unpack_565 (bgr ); } 990 premul(F32 * r,F32 * g,F32 * b,F32 a)991 static inline void premul(F32* r, F32* g, F32* b, F32 a) { a-> premul(r,g,b,a); } unpremul(F32 * r,F32 * g,F32 * b,F32 a)992 static inline void unpremul(F32* r, F32* g, F32* b, F32 a) { a->unpremul(r,g,b,a); } 993 premul(Color c)994 static inline Color premul(Color c) { return c-> premul(c); } unpremul(Color c)995 static inline Color unpremul(Color c) { return c->unpremul(c); } 996 lerp(Color lo,Color hi,F32 t)997 static inline Color lerp(Color lo, Color hi, F32 t) { return t->lerp(lo,hi,t); } 998 blend(SkBlendMode m,Color s,Color d)999 static inline Color blend(SkBlendMode m, Color s, Color d) { return s->blend(m,s,d); } 1000 to_hsla(Color c)1001 static inline HSLA to_hsla(Color c) { return c->to_hsla(c); } to_rgba(HSLA c)1002 static inline Color to_rgba(HSLA c) { return c->to_rgba(c); } 1003 } 1004 1005 #endif//SkVM_DEFINED 1006