paint color -> shader
This means we can share programs with color shaders whether they come through as a paint color or shader. The GM now only ever JITs one program. Change-Id: If61f9e7b79aa6b8fd1de7c16ff52f78bfd7dc4ec Reviewed-on: https://skia-review.googlesource.com/c/skia/+/252079 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
476061e4ce
commit
9d0c67ab1b
26
gm/skvm.cpp
26
gm/skvm.cpp
@ -17,27 +17,29 @@
|
||||
DEF_SIMPLE_GM(SkVMBlitter, canvas, 100, 100) {
|
||||
SkPaint p;
|
||||
|
||||
// These two draws are supported by SkVMBlitter,
|
||||
// and the green draw will reuse the program cached by the blue draw.
|
||||
// These three draws are supported by SkVMBlitter,
|
||||
// and the later draws will reuse the program 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 calls to done, one for the blitter that clears to white,
|
||||
// and one for the program used by both shader draws.
|
||||
// You should see 1 call to done.
|
||||
//
|
||||
// $ ninja -C out fm && out/fm -b cpu -s SkVMBlitter
|
||||
// ...
|
||||
// 2 calls to done
|
||||
// 1 calls to done
|
||||
//
|
||||
// Clever readers might realize this could actually be one single blitter:
|
||||
// only the fact that some colors come via shader and the white clear via
|
||||
// the paint makes the two programs cache differently, despite basically
|
||||
// doing the same thing. (TODO: unify these two paths also so they'd hit
|
||||
// the cache.)
|
||||
// The program is actually first 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.
|
||||
|
||||
p.setShader(SkShaders::Color(SK_ColorBLUE));
|
||||
canvas->drawRect({0,0,50,50}, p);
|
||||
canvas->drawRect({0,0, 50,50}, p);
|
||||
|
||||
p.setShader(SkShaders::Color(SK_ColorGREEN));
|
||||
canvas->drawRect({50,50,100,100}, p);
|
||||
canvas->drawRect({50,50, 100,100}, p);
|
||||
|
||||
p.setShader(nullptr);
|
||||
p.setColor(SK_ColorRED);
|
||||
canvas->drawRect({0,50, 50,100}, p);
|
||||
}
|
||||
|
@ -116,8 +116,8 @@ namespace {
|
||||
|
||||
|
||||
struct Uniforms {
|
||||
uint32_t paint_color;
|
||||
uint8_t coverage; // Used when Coverage::UniformA8.
|
||||
uint8_t padding[3]; // Keep 32-bit aligned.
|
||||
};
|
||||
|
||||
struct Builder : public skvm::Builder {
|
||||
@ -185,14 +185,16 @@ namespace {
|
||||
|
||||
static bool CanBuild(const Params& params) {
|
||||
// These checks parallel the TODOs in Builder::Builder().
|
||||
if (params.shader) {
|
||||
// TODO: probably want to pass all of the device's SkColorInfo?
|
||||
if (!as_SB(params.shader)->program(nullptr,
|
||||
params.colorSpace.get(),
|
||||
skvm::Arg{0}, 0,
|
||||
nullptr,nullptr,nullptr,nullptr)) {
|
||||
return false;
|
||||
SkASSERT(params.shader);
|
||||
// TODO: probably want to pass all of the device's SkColorInfo?
|
||||
if (!as_SB(params.shader)->program(nullptr,
|
||||
params.colorSpace.get(),
|
||||
skvm::Arg{0}, 0,
|
||||
nullptr,nullptr,nullptr,nullptr)) {
|
||||
if (debug_dump(key(params))) {
|
||||
SkDebugf("%s not yet supported\n", params.shader->getTypeName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (params.colorType) {
|
||||
@ -221,13 +223,12 @@ namespace {
|
||||
// If coverage is Mask3D there'll next come two varyings for mul and add planes,
|
||||
// and then finally if coverage is any Mask?? format, a varying for the mask.
|
||||
|
||||
Color src = unpack_8888(uniform32(uniforms, offsetof(Uniforms, paint_color)));
|
||||
if (params.shader) {
|
||||
SkAssertResult(as_SB(params.shader)->program(this,
|
||||
params.colorSpace.get(),
|
||||
uniforms, sizeof(Uniforms),
|
||||
&src.r, &src.g, &src.b, &src.a));
|
||||
}
|
||||
Color src;
|
||||
SkASSERT(params.shader);
|
||||
SkAssertResult(as_SB(params.shader)->program(this,
|
||||
params.colorSpace.get(),
|
||||
uniforms, sizeof(Uniforms),
|
||||
&src.r, &src.g, &src.b, &src.a));
|
||||
|
||||
if (params.coverage == Coverage::Mask3D) {
|
||||
skvm::I32 M = load8(varying<uint8_t>()),
|
||||
@ -392,9 +393,16 @@ namespace {
|
||||
const char* getTypeName() const override { return "AlphaShader"; }
|
||||
};
|
||||
|
||||
static sk_sp<SkShader> alpha_shader(sk_sp<SkShader> shader, uint8_t alpha) {
|
||||
return (shader && alpha < 0xff) ? sk_make_sp<AlphaShader>(std::move(shader), alpha)
|
||||
: std::move(shader);
|
||||
static sk_sp<SkShader> effective_shader(sk_sp<SkShader> shader, SkColor4f paintColor) {
|
||||
// When there's no shader, the paint color becomes the shader.
|
||||
if (!shader) {
|
||||
return SkShaders::Color(paintColor, nullptr);
|
||||
}
|
||||
|
||||
// When there is a shader, we modulate it by the paint's alpha.
|
||||
uint8_t alpha = paintColor.toBytes_RGBA() >> 24;
|
||||
return alpha < 0xff ? sk_make_sp<AlphaShader>(std::move(shader), alpha)
|
||||
: std::move(shader);
|
||||
}
|
||||
|
||||
class Blitter final : public SkBlitter {
|
||||
@ -405,7 +413,7 @@ namespace {
|
||||
: fDevice(device)
|
||||
, fParams {
|
||||
device.refColorSpace(),
|
||||
alpha_shader(paint.refShader(), paint.getAlpha()),
|
||||
effective_shader(paint.refShader(), paint.getColor4f()),
|
||||
device.colorType(),
|
||||
device.alphaType(),
|
||||
paint.getBlendMode(),
|
||||
@ -416,16 +424,7 @@ namespace {
|
||||
{
|
||||
// Color filters have been folded back into shader and/or paint color by now.
|
||||
SkASSERT(!paint.getColorFilter());
|
||||
|
||||
SkColor4f color = paint.getColor4f();
|
||||
SkColorSpaceXformSteps{sk_srgb_singleton(), kUnpremul_SkAlphaType,
|
||||
device.colorSpace(), kUnpremul_SkAlphaType}.apply(color.vec());
|
||||
|
||||
if (color.fitsInBytes() && Builder::CanBuild(fParams)) {
|
||||
uint32_t rgba = color.premul().toBytes_RGBA();
|
||||
memcpy(fUniforms.data() + offsetof(Uniforms, paint_color), &rgba, sizeof(rgba));
|
||||
ok = true;
|
||||
}
|
||||
ok = Builder::CanBuild(fParams);
|
||||
}
|
||||
|
||||
~Blitter() override {
|
||||
|
@ -90,14 +90,13 @@ bool SkColor4Shader::onAppendStages(const SkStageRec& rec) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkColorShader::program(skvm::Builder* p,
|
||||
SkColorSpace* dstCS,
|
||||
skvm::Arg uniforms, int offset,
|
||||
skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const {
|
||||
|
||||
SkColor4f color = SkColor4f::FromColor(fColor);
|
||||
SkColorSpaceXformSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
|
||||
dstCS, kUnpremul_SkAlphaType).apply(color.vec());
|
||||
static bool common_program(SkColor4f color, SkColorSpace* cs,
|
||||
skvm::Builder* p,
|
||||
SkColorSpace* dstCS,
|
||||
skvm::Arg uniforms, int offset,
|
||||
skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) {
|
||||
SkColorSpaceXformSteps( cs, kUnpremul_SkAlphaType,
|
||||
dstCS, kUnpremul_SkAlphaType).apply(color.vec());
|
||||
|
||||
if (color.fitsInBytes()) {
|
||||
if (p) {
|
||||
@ -111,11 +110,10 @@ bool SkColorShader::program(skvm::Builder* p,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SkColorShader::uniforms(SkColorSpace* dstCS, uint8_t* uniform_buffer) const {
|
||||
SkColor4f color = SkColor4f::FromColor(fColor);
|
||||
SkColorSpaceXformSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
|
||||
dstCS, kUnpremul_SkAlphaType).apply(color.vec());
|
||||
static size_t common_uniforms(SkColor4f color, SkColorSpace* cs,
|
||||
SkColorSpace* dstCS, uint8_t* uniform_buffer) {
|
||||
SkColorSpaceXformSteps( cs, kUnpremul_SkAlphaType,
|
||||
dstCS, kUnpremul_SkAlphaType).apply(color.vec());
|
||||
|
||||
SkASSERT(color.fitsInBytes());
|
||||
|
||||
@ -126,6 +124,29 @@ size_t SkColorShader::uniforms(SkColorSpace* dstCS, uint8_t* uniform_buffer) con
|
||||
return sizeof(rgba);
|
||||
}
|
||||
|
||||
bool SkColorShader::program(skvm::Builder* p,
|
||||
SkColorSpace* dstCS,
|
||||
skvm::Arg uniforms, int offset,
|
||||
skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const {
|
||||
return common_program(SkColor4f::FromColor(fColor), sk_srgb_singleton(),
|
||||
p, dstCS, uniforms, offset, r,g,b,a);
|
||||
}
|
||||
bool SkColor4Shader::program(skvm::Builder* p,
|
||||
SkColorSpace* dstCS,
|
||||
skvm::Arg uniforms, int offset,
|
||||
skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const {
|
||||
return common_program(fColor, fColorSpace.get(),
|
||||
p, dstCS, uniforms, offset, r,g,b,a);
|
||||
}
|
||||
|
||||
size_t SkColorShader::uniforms(SkColorSpace* dstCS, uint8_t* uniform_buffer) const {
|
||||
return common_uniforms(SkColor4f::FromColor(fColor), sk_srgb_singleton(),
|
||||
dstCS, uniform_buffer);
|
||||
}
|
||||
size_t SkColor4Shader::uniforms(SkColorSpace* dstCS, uint8_t* uniform_buffer) const {
|
||||
return common_uniforms(fColor, fColorSpace.get(),
|
||||
dstCS, uniform_buffer);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
|
@ -70,6 +70,12 @@ private:
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
bool onAppendStages(const SkStageRec&) const override;
|
||||
|
||||
bool program(skvm::Builder*,
|
||||
SkColorSpace* dstCS,
|
||||
skvm::Arg uniforms, int offset,
|
||||
skvm::I32* r, skvm::I32* g, skvm::I32* b, skvm::I32* a) const override;
|
||||
size_t uniforms(SkColorSpace* dstCS, uint8_t* uniform_buffer) const override;
|
||||
|
||||
sk_sp<SkColorSpace> fColorSpace;
|
||||
const SkColor4f fColor;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user