Add ceil to skvx/skvm/JIT, and floor/ceil intrinsics to ByteCode

This is enough to get the colorcube GM working on the CPU backend.
(It's not blazingly fast, but it works!)

Change-Id: Ic069861bab162ed49f876fd03af2cbaaec2da628
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/297718
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2020-06-18 17:11:16 -04:00 committed by Skia Commit-Bot
parent df4e3ab185
commit 89bf734d87
8 changed files with 41 additions and 9 deletions

View File

@ -279,12 +279,7 @@ class ColorCubeRT : public skiagm::GM {
SkISize onISize() override { return {512, 512}; }
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (canvas->getGrContext() == nullptr) {
// until SkSL can handle child processors on the raster backend
return DrawResult::kSkip;
}
void onDraw(SkCanvas* canvas) override {
// First we draw the unmodified image, and a copy that was sepia-toned in Photoshop:
canvas->drawImage(fMandrill, 0, 0);
canvas->drawImage(fMandrillSepia, 0, 256);
@ -319,8 +314,6 @@ class ColorCubeRT : public skiagm::GM {
paint.setShader(builder.makeShader(nullptr, true));
canvas->translate(0, 256);
canvas->drawRect({ 0, 0, 256, 256 }, paint);
return DrawResult::kOk;
}
};
DEF_GM(return new ColorCubeRT;)

View File

@ -673,6 +673,16 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
case Inst::kATan3:
case Inst::kATan4: unary(Inst::kATan, skvm::approx_atan); break;
case Inst::kCeil:
case Inst::kCeil2:
case Inst::kCeil3:
case Inst::kCeil4: unary(Inst::kCeil, skvm::ceil); break;
case Inst::kFloor:
case Inst::kFloor2:
case Inst::kFloor3:
case Inst::kFloor4: unary(Inst::kFloor, skvm::floor); break;
case Inst::kFract:
case Inst::kFract2:
case Inst::kFract3:

View File

@ -250,6 +250,7 @@ namespace skvm {
case Op::select: write(o, V{id}, "=", op, V{x}, V{y}, V{z}, fs(id)...); break;
case Op::pack: write(o, V{id}, "=", op, V{x}, V{y}, Shift{immz}, fs(id)...); break;
case Op::ceil: write(o, V{id}, "=", op, V{x}, fs(id)...); break;
case Op::floor: write(o, V{id}, "=", op, V{x}, fs(id)...); break;
case Op::to_f32: write(o, V{id}, "=", op, V{x}, fs(id)...); break;
case Op::trunc: write(o, V{id}, "=", op, V{x}, fs(id)...); break;
@ -369,6 +370,7 @@ namespace skvm {
case Op::select: write(o, R{d}, "=", op, R{x}, R{y}, R{z}); break;
case Op::pack: write(o, R{d}, "=", op, R{x}, R{y}, Shift{immz}); break;
case Op::ceil: write(o, R{d}, "=", op, R{x}); break;
case Op::floor: write(o, R{d}, "=", op, R{x}); break;
case Op::to_f32: write(o, R{d}, "=", op, R{x}); break;
case Op::trunc: write(o, R{d}, "=", op, R{x}); break;
@ -1013,6 +1015,10 @@ namespace skvm {
return {this, this->push(Op::pack, x.id,y.id,NA, 0,bits)};
}
F32 Builder::ceil(F32 x) {
if (float X; this->allImm(x.id,&X)) { return splat(ceilf(X)); }
return {this, this->push(Op::ceil, x.id)};
}
F32 Builder::floor(F32 x) {
if (float X; this->allImm(x.id,&X)) { return splat(floorf(X)); }
return {this, this->push(Op::floor, x.id)};
@ -2352,6 +2358,9 @@ namespace skvm {
F(vals[z])}));
break;
case Op::ceil:
vals[i] = I(b->CreateUnaryIntrinsic(llvm::Intrinsic::ceil, F(vals[x])));
break;
case Op::floor:
vals[i] = I(b->CreateUnaryIntrinsic(llvm::Intrinsic::floor, F(vals[x])));
break;
@ -3223,6 +3232,11 @@ namespace skvm {
a->vpor (dst(), dst(), any(x));
break;
case Op::ceil:
if (in_reg(x)) { a->vroundps(dst(x), r(x), Assembler::CEIL); }
else { a->vroundps(dst(), any(x), Assembler::CEIL); }
break;
case Op::floor:
if (in_reg(x)) { a->vroundps(dst(x), r(x), Assembler::FLOOR); }
else { a->vroundps(dst(), any(x), Assembler::FLOOR); }

View File

@ -387,7 +387,8 @@ namespace skvm {
M(fma_f32) M(fms_f32) M(fnma_f32) \
M(sqrt_f32) \
M(shl_i32) M(shr_i32) M(sra_i32) \
M(floor) M(trunc) M(round) M(to_f32) \
M(ceil) M(floor) M(trunc) M(round) \
M(to_f32) \
M( eq_f32) M( eq_i32) \
M(neq_f32) \
M( gt_f32) M( gt_i32) \
@ -642,6 +643,7 @@ namespace skvm {
F32 abs(F32 x) { return bit_cast(bit_and(bit_cast(x), 0x7fff'ffff)); }
F32 fract(F32 x) { return sub(x, floor(x)); }
F32 ceil(F32);
F32 floor(F32);
I32 is_NaN(F32 x) { return neq(x,x); }
@ -978,6 +980,7 @@ namespace skvm {
static inline F32 clamp01(F32 x) { return x->clamp01(x); }
static inline F32 abs(F32 x) { return x-> abs(x); }
static inline F32 ceil(F32 x) { return x-> ceil(x); }
static inline F32 fract(F32 x) { return x-> fract(x); }
static inline F32 floor(F32 x) { return x-> floor(x); }
static inline I32 is_NaN(F32 x) { return x-> is_NaN(x); }

View File

@ -229,6 +229,7 @@ namespace SK_OPTS_NS {
CASE(Op::pack): r(d).u32 = r(x).u32 | (r(y).u32 << immz); break;
CASE(Op::ceil): r(d).f32 = skvx::ceil(r(x).f32) ; break;
CASE(Op::floor): r(d).f32 = skvx::floor(r(x).f32) ; break;
CASE(Op::to_f32): r(d).f32 = skvx::cast<float>( r(x).i32 ); break;
CASE(Op::trunc): r(d).i32 = skvx::cast<int> ( r(x).f32 ); break;

View File

@ -61,6 +61,7 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) {
printf("callexternal %d, %d, %d", argumentCount, returnCount, externalValue);
break;
}
VECTOR_DISASSEMBLE(kCeil, "ceil")
case ByteCodeInstruction::kClampIndex: printf("clampindex %d", READ8()); break;
VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq")
VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq")
@ -86,6 +87,7 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) {
VECTOR_DISASSEMBLE(kDivideS, "divideS")
VECTOR_DISASSEMBLE(kDivideU, "divideu")
VECTOR_MATRIX_DISASSEMBLE(kDup, "dup")
VECTOR_DISASSEMBLE(kFloor, "floor")
VECTOR_DISASSEMBLE(kFract, "fract")
case ByteCodeInstruction::kInverse2x2: printf("inverse2x2"); break;
case ByteCodeInstruction::kInverse3x3: printf("inverse3x3"); break;
@ -553,6 +555,8 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue
continue;
}
VECTOR_UNARY_FN(kCeil, skvx::ceil, fFloat)
case ByteCodeInstruction::kClampIndex: {
int length = READ8();
if (skvx::any(mask() & ((sp[0].fSigned < 0) | (sp[0].fSigned >= length)))) {
@ -643,6 +647,7 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue
continue;
}
VECTOR_UNARY_FN(kFloor, skvx::floor, fFloat)
VECTOR_UNARY_FN(kFract, skvx::fract, fFloat)
case ByteCodeInstruction::kInverse2x2:

View File

@ -34,6 +34,7 @@ enum class ByteCodeInstruction : uint16_t {
// Followed by three bytes indicating: the number of argument slots, the number of return slots,
// and the index of the external value to call
kCallExternal,
VECTOR(kCeil),
// For dynamic array access: Followed by byte indicating length of array
kClampIndex,
VECTOR(kCompareIEQ),
@ -61,6 +62,7 @@ enum class ByteCodeInstruction : uint16_t {
VECTOR(kDivideU),
// Duplicates the top stack value
VECTOR_MATRIX(kDup),
VECTOR(kFloor),
VECTOR(kFract),
kInverse2x2,
kInverse3x3,

View File

@ -47,9 +47,11 @@ ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* prog
// You can probably copy the declarations from sksl_gpu.inc.
, fIntrinsics {
{ "atan", ByteCodeInstruction::kATan },
{ "ceil", ByteCodeInstruction::kCeil },
{ "clamp", SpecialIntrinsic::kClamp },
{ "cos", ByteCodeInstruction::kCos },
{ "dot", SpecialIntrinsic::kDot },
{ "floor", ByteCodeInstruction::kFloor },
{ "fract", ByteCodeInstruction::kFract },
{ "inverse", ByteCodeInstruction::kInverse2x2 },
{ "length", SpecialIntrinsic::kLength },
@ -257,7 +259,9 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
VECTOR_UNARY_OP(kConvertUtoF)
VECTOR_UNARY_OP(kATan)
VECTOR_UNARY_OP(kCeil)
VECTOR_UNARY_OP(kCos)
VECTOR_UNARY_OP(kFloor)
VECTOR_UNARY_OP(kFract)
VECTOR_UNARY_OP(kSin)
VECTOR_UNARY_OP(kSqrt)