cfa4f60270
By making uniforms() just append to the uniform vector, there's no more need for two passes, no need for the blitter to ever even know how many uniforms the effects use, and the effects now never need to deal with a nullptr uniform buffer. Much simpler all around. While we're refactoring, convert the uniform buffer de jure to std::vector<uint32_t>, which is what we'd been treating the old std::vector<uint8_t> as by convention, and switch the program() offset parameter type to size_t as a reminder that it's measured in bytes. Cq-Include-Trybots: skia.primary:Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_SKVM_BLITTER Change-Id: I81d2c92aae37a650104f384f815df78c8a186270 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252776 Reviewed-by: Mike Klein <mtklein@google.com>
133 lines
4.7 KiB
C++
133 lines
4.7 KiB
C++
/*
|
|
* 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"
|
|
#include "src/core/SkReadBuffer.h"
|
|
#include "src/core/SkWriteBuffer.h"
|
|
#include "src/shaders/SkShaderBase.h"
|
|
|
|
// 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.
|
|
|
|
// 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, size_t 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)) {
|
|
// 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;
|
|
}
|
|
|
|
void uniforms(SkColorSpace* dstCS, std::vector<uint32_t>* buf) const override {
|
|
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;
|
|
|
|
DEF_SIMPLE_GM(SkVMBlitter, canvas, 100, 100) {
|
|
SkPaint p;
|
|
|
|
// These draws are all supported by SkVMBlitter,
|
|
// and the some draws will reuse programs cached by earlier draws.
|
|
//
|
|
// 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.
|
|
// You should see 2 call to done.
|
|
//
|
|
// $ ninja -C out fm && out/fm -b cpu -s SkVMBlitter
|
|
// ...
|
|
// 2 calls to done
|
|
//
|
|
// The first program is actually created when the GM framework first
|
|
// 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.
|
|
//
|
|
// The second program handles the draw with the Fade shader.
|
|
|
|
/*
|
|
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:
|
|
store32 arg(1) r1
|
|
*/
|
|
p.setShader(SkShaders::Color(SK_ColorBLUE));
|
|
canvas->drawRect({0,0, 50,50}, p);
|
|
|
|
p.setShader(SkShaders::Color(SK_ColorGREEN));
|
|
canvas->drawRect({50,50, 100,100}, p);
|
|
|
|
p.setShader(nullptr);
|
|
p.setColor(SK_ColorRED);
|
|
canvas->drawRect({0,50, 50,100}, p);
|
|
|
|
/*
|
|
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:
|
|
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
|
|
*/
|
|
p.setShader(sk_make_sp<Fade>(SkShaders::Color(SK_ColorYELLOW)));
|
|
canvas->drawRect({50,0, 100,50}, p);
|
|
}
|