2019-10-31 19:55:55 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2019 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gm/gm.h"
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
|
|
#include "include/core/SkPaint.h"
|
|
|
|
#include "include/core/SkShader.h"
|
2019-11-04 19:22:02 +00:00
|
|
|
#include "src/core/SkReadBuffer.h"
|
|
|
|
#include "src/core/SkWriteBuffer.h"
|
|
|
|
#include "src/shaders/SkShaderBase.h"
|
2019-10-31 19:55:55 +00:00
|
|
|
|
|
|
|
// This GM exercises interesting cases in SkVMBlitter,
|
|
|
|
// and mostly draws uninteresting simple shapes and colors.
|
|
|
|
// At the moment it's really only interesting if you #define SK_USE_SKVM_BLITTER.
|
|
|
|
|
2019-11-04 19:22:02 +00:00
|
|
|
// Just a tiny example that the (x,y) coordinate parameters are vaguely working.
|
|
|
|
// In this case we'll fade the red channel over its span vertically using `y`,
|
|
|
|
// and green horizontally using `x`.
|
|
|
|
struct Fade : public SkShaderBase {
|
|
|
|
explicit Fade(sk_sp<SkShader> shader) : fShader(std::move(shader)) {}
|
|
|
|
|
|
|
|
sk_sp<SkShader> fShader;
|
|
|
|
|
|
|
|
bool isOpaque() const override { return fShader->isOpaque(); }
|
|
|
|
|
|
|
|
bool onProgram(skvm::Builder* p,
|
|
|
|
SkColorSpace* dstCS,
|
|
|
|
skvm::Arg uniforms, int offset,
|
|
|
|
skvm::F32 x, skvm::F32 y,
|
|
|
|
skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const override {
|
|
|
|
if (as_SB(fShader)->program(p, dstCS,
|
|
|
|
uniforms, offset,
|
|
|
|
x,y, r,g,b,a)) {
|
|
|
|
if (p) {
|
|
|
|
// In this GM `y` will range over 0-50 and `x` over 50-100.
|
|
|
|
*r = p->to_i32(p->mul(y, p->splat(255/ 50.0f)));
|
|
|
|
*g = p->to_i32(p->mul(x, p->splat(255/100.0f)));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t uniforms(SkColorSpace* dstCS, uint8_t* buf) const override {
|
|
|
|
return as_SB(fShader)->uniforms(dstCS, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flattening is not really necessary, just nice to make serialize-8888 etc. not crash.
|
|
|
|
void flatten(SkWriteBuffer& b) const override {
|
|
|
|
b.writeFlattenable(fShader.get());
|
|
|
|
}
|
|
|
|
SK_FLATTENABLE_HOOKS(Fade)
|
|
|
|
};
|
|
|
|
sk_sp<SkFlattenable> Fade::CreateProc(SkReadBuffer& b) {
|
|
|
|
return sk_make_sp<Fade>(b.readShader());
|
|
|
|
}
|
|
|
|
static struct RegisterFade {
|
|
|
|
RegisterFade() { SkFlattenable::Register("Fade", Fade::CreateProc); }
|
|
|
|
} now;
|
|
|
|
|
2019-10-31 19:55:55 +00:00
|
|
|
DEF_SIMPLE_GM(SkVMBlitter, canvas, 100, 100) {
|
|
|
|
SkPaint p;
|
|
|
|
|
2019-11-04 19:22:02 +00:00
|
|
|
// These draws are all supported by SkVMBlitter,
|
|
|
|
// and the some draws will reuse programs cached by earlier draws.
|
2019-10-31 19:55:55 +00:00
|
|
|
//
|
|
|
|
// We don't have any API to detect this, but you can flip on the #if guard
|
|
|
|
// around "calls to done" in SkVMBlitter.cpp and run this GM in isolation.
|
2019-11-04 19:22:02 +00:00
|
|
|
// You should see 2 call to done.
|
2019-10-31 19:55:55 +00:00
|
|
|
//
|
|
|
|
// $ ninja -C out fm && out/fm -b cpu -s SkVMBlitter
|
|
|
|
// ...
|
2019-11-04 19:22:02 +00:00
|
|
|
// 2 calls to done
|
2019-10-31 19:55:55 +00:00
|
|
|
//
|
2019-11-04 19:22:02 +00:00
|
|
|
// The first program is actually created when the GM framework first
|
2019-10-31 20:41:58 +00:00
|
|
|
// clears the buffer white by setting a paint color to SK_ColorWHITE like
|
|
|
|
// we do with SK_ColorRED. SkVMBlitter is clever enough now to build the
|
|
|
|
// same program for paint colors or color shaders.
|
2019-11-04 19:22:02 +00:00
|
|
|
//
|
|
|
|
// The second program handles the draw with the Fade shader.
|
2019-10-31 19:55:55 +00:00
|
|
|
|
2019-11-04 19:22:02 +00:00
|
|
|
/*
|
|
|
|
4 registers, 9 instructions:
|
|
|
|
r0 = uniform32 arg(0) 8
|
|
|
|
r1 = splat FF (3.5733111e-43)
|
|
|
|
r2 = extract r0 0 r1
|
|
|
|
r3 = extract r0 8 r1
|
|
|
|
r3 = pack r2 r3 8
|
|
|
|
r0 = extract r0 16 r1
|
|
|
|
r1 = pack r0 r1 8
|
|
|
|
r1 = pack r3 r1 16
|
|
|
|
loop:
|
2019-11-05 02:14:24 +00:00
|
|
|
store32 arg(1) r1
|
2019-11-04 19:22:02 +00:00
|
|
|
*/
|
2019-10-31 19:55:55 +00:00
|
|
|
p.setShader(SkShaders::Color(SK_ColorBLUE));
|
2019-10-31 20:41:58 +00:00
|
|
|
canvas->drawRect({0,0, 50,50}, p);
|
2019-10-31 19:55:55 +00:00
|
|
|
|
|
|
|
p.setShader(SkShaders::Color(SK_ColorGREEN));
|
2019-10-31 20:41:58 +00:00
|
|
|
canvas->drawRect({50,50, 100,100}, p);
|
|
|
|
|
|
|
|
p.setShader(nullptr);
|
|
|
|
p.setColor(SK_ColorRED);
|
|
|
|
canvas->drawRect({0,50, 50,100}, p);
|
2019-11-04 19:22:02 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
5 registers, 19 instructions:
|
|
|
|
r0 = uniform32 arg(0) 4 // load y
|
|
|
|
r0 = to_f32 r0
|
|
|
|
r1 = splat 40A33333 (5.0999999)
|
|
|
|
r1 = mul_f32 r0 r1
|
|
|
|
r1 = to_i32 r1 // r1 = red channel, depends on y, is uniform
|
|
|
|
r0 = uniform32 arg(0) 0 // load right edge, used to calculate x in loop
|
|
|
|
r2 = splat 40233333 (2.55)
|
|
|
|
r3 = splat FF (3.5733111e-43) // color shader alpha, known to be opaque
|
|
|
|
r4 = uniform32 arg(0) 8 // load color shader for blue
|
|
|
|
r4 = extract r4 16 r3 // extract blue
|
|
|
|
r3 = pack r4 r3 8 // r3 = blue and alpha from color shader
|
|
|
|
loop:
|
2019-11-05 02:14:24 +00:00
|
|
|
r4 = index
|
|
|
|
r4 = sub_i32 r0 r4 // r4 = x
|
|
|
|
r4 = to_f32 r4
|
|
|
|
r4 = mul_f32 r4 r2
|
|
|
|
r4 = to_i32 r4 // r4 = green channel, depends on x, is varying
|
|
|
|
r4 = pack r1 r4 8
|
|
|
|
r4 = pack r4 r3 16
|
|
|
|
store32 arg(1) r4
|
2019-11-04 19:22:02 +00:00
|
|
|
*/
|
|
|
|
p.setShader(sk_make_sp<Fade>(SkShaders::Color(SK_ColorYELLOW)));
|
|
|
|
canvas->drawRect({50,0, 100,50}, p);
|
2019-10-31 19:55:55 +00:00
|
|
|
}
|