Skip to content

Commit e965438

Browse files
reed-at-googleSkia Commit-Bot
authored andcommitted
implement more blendmodes for skvm
Change-Id: Ib7286235249f9b4027c1c59c9fae268a9dffefcd Reviewed-on: https://skia-review.googlesource.com/c/skia/+/278096 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Reed <reed@google.com>
1 parent 9339266 commit e965438

File tree

4 files changed

+169
-72
lines changed

4 files changed

+169
-72
lines changed

src/core/SkBlendModePriv.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include "include/core/SkBlendMode.h"
1212
#include "include/core/SkColor.h"
1313
#include "include/private/SkColorData.h"
14-
#include "src/core/SkVM.h"
1514

1615
class SkRasterPipeline;
1716

@@ -31,9 +30,4 @@ SkPMColor4f SkBlendMode_Apply(SkBlendMode, const SkPMColor4f& src, const SkPMCol
3130
const GrXPFactory* SkBlendMode_AsXPFactory(SkBlendMode);
3231
#endif
3332

34-
namespace skvm {
35-
bool BlendModeSupported(SkBlendMode);
36-
Color BlendModeProgram(Builder*, SkBlendMode, Color src, Color dst);
37-
}
38-
3933
#endif

src/core/SkVM.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#ifndef SkVM_DEFINED
99
#define SkVM_DEFINED
1010

11-
#include "include/core/SkTypes.h"
11+
#include "include/core/SkBlendMode.h"
1212
#include "include/private/SkMacros.h"
1313
#include "include/private/SkTHash.h"
1414
#include "src/core/SkVM_fwd.h"
@@ -566,6 +566,7 @@ namespace skvm {
566566
Color premul(Color c) { this->premul(&c.r, &c.g, &c.b, c.a); return c; }
567567
Color unpremul(Color c) { this->unpremul(&c.r, &c.g, &c.b, c.a); return c; }
568568
Color lerp(Color lo, Color hi, F32 t);
569+
Color blend(SkBlendMode, Color src, Color dst);
569570

570571
void dump(SkWStream* = nullptr) const;
571572
void dot (SkWStream* = nullptr, bool for_jit=false) const;
@@ -689,6 +690,8 @@ namespace skvm {
689690
std::unique_ptr<Impl> fImpl;
690691
};
691692

693+
bool BlendModeSupported(SkBlendMode);
694+
692695
// TODO: control flow
693696
// TODO: 64-bit values?
694697
// TODO: SSE2/SSE4.1, AVX-512F, ARMv8.2 JITs?

src/core/SkVMBlitter.cpp

Lines changed: 164 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ namespace {
332332
premul(&dst.r, &dst.g, &dst.b, dst.a);
333333
}
334334

335-
src = skvm::BlendModeProgram(this, params.blendMode, src, dst);
335+
src = this->blend(params.blendMode, src, dst);
336336

337337
// Lerp with coverage post-blend if needed.
338338
if (skvm::Color cov; lerp_coverage_post_blend && load_coverage(&cov)) {
@@ -729,93 +729,193 @@ namespace {
729729
} // namespace
730730

731731
bool skvm::BlendModeSupported(SkBlendMode mode) {
732-
return mode <= SkBlendMode::kScreen;
732+
switch (mode) {
733+
default: break;
734+
// our todo list
735+
case SkBlendMode::kHue:
736+
case SkBlendMode::kSaturation:
737+
case SkBlendMode::kColor:
738+
case SkBlendMode::kLuminosity:
739+
return false;
740+
}
741+
return true;
733742
}
734743

735-
skvm::Color skvm::BlendModeProgram(skvm::Builder* p,
736-
SkBlendMode mode, skvm::Color src, skvm::Color dst) {
737-
auto mma = [&](skvm::F32 x, skvm::F32 y, skvm::F32 z, skvm::F32 w) {
738-
return p->mad(x,y, p->mul(z,w));
744+
skvm::Color skvm::Builder::blend(SkBlendMode mode, Color src, Color dst) {
745+
auto mma = [this](skvm::F32 x, skvm::F32 y, skvm::F32 z, skvm::F32 w) {
746+
return mad(x,y, mul(z,w));
747+
};
748+
749+
auto inv = [this](skvm::F32 x) { return sub(splat(1.0f), x); };
750+
751+
auto two = [this](skvm::F32 x) { return add(x, x); };
752+
753+
auto apply_rgba = [&](auto fn) {
754+
return Color {
755+
fn(src.r, dst.r),
756+
fn(src.g, dst.g),
757+
fn(src.b, dst.b),
758+
fn(src.a, dst.a),
759+
};
739760
};
740761

741-
auto inv = [&](skvm::F32 x) {
742-
return p->sub(p->splat(1.0f), x);
762+
auto apply_rgb_srcover_a = [&](auto fn) {
763+
return Color {
764+
fn(src.r, dst.r),
765+
fn(src.g, dst.g),
766+
fn(src.b, dst.b),
767+
mad(dst.a, inv(src.a), src.a), // srcover for alpha
768+
};
743769
};
744770

745771
switch (mode) {
746772
default: SkASSERT(false); /*but also, for safety, fallthrough*/
747773

748774
case SkBlendMode::kClear: return {
749-
p->splat(0.0f),
750-
p->splat(0.0f),
751-
p->splat(0.0f),
752-
p->splat(0.0f),
775+
splat(0.0f),
776+
splat(0.0f),
777+
splat(0.0f),
778+
splat(0.0f),
753779
};
754780

755781
case SkBlendMode::kSrc: return src;
756782
case SkBlendMode::kDst: return dst;
757783

758784
case SkBlendMode::kDstOver: std::swap(src, dst); // fall-through
759-
case SkBlendMode::kSrcOver: return {
760-
p->mad(dst.r, inv(src.a), src.r),
761-
p->mad(dst.g, inv(src.a), src.g),
762-
p->mad(dst.b, inv(src.a), src.b),
763-
p->mad(dst.a, inv(src.a), src.a),
764-
};
785+
case SkBlendMode::kSrcOver:
786+
return apply_rgba([&](auto s, auto d) {
787+
return mad(d, inv(src.a), s);
788+
});
765789

766790
case SkBlendMode::kDstIn: std::swap(src, dst); // fall-through
767-
case SkBlendMode::kSrcIn: return {
768-
p->mul(src.r, dst.a),
769-
p->mul(src.g, dst.a),
770-
p->mul(src.b, dst.a),
771-
p->mul(src.a, dst.a),
772-
};
791+
case SkBlendMode::kSrcIn:
792+
return apply_rgba([&](auto s, auto d) {
793+
return mul(s, dst.a);
794+
});
773795

774796
case SkBlendMode::kDstOut: std::swap(src, dst); // fall-through
775-
case SkBlendMode::kSrcOut: return {
776-
p->mul(src.r, inv(dst.a)),
777-
p->mul(src.g, inv(dst.a)),
778-
p->mul(src.b, inv(dst.a)),
779-
p->mul(src.a, inv(dst.a)),
780-
};
797+
case SkBlendMode::kSrcOut:
798+
return apply_rgba([&](auto s, auto d) {
799+
return mul(s, inv(dst.a));
800+
});
781801

782802
case SkBlendMode::kDstATop: std::swap(src, dst); // fall-through
783-
case SkBlendMode::kSrcATop: return {
784-
mma(src.r, dst.a, dst.r, inv(src.a)),
785-
mma(src.g, dst.a, dst.g, inv(src.a)),
786-
mma(src.b, dst.a, dst.b, inv(src.a)),
787-
mma(src.a, dst.a, dst.a, inv(src.a)),
788-
};
789-
790-
case SkBlendMode::kXor: return {
791-
mma(src.r, inv(dst.a), dst.r, inv(src.a)),
792-
mma(src.g, inv(dst.a), dst.g, inv(src.a)),
793-
mma(src.b, inv(dst.a), dst.b, inv(src.a)),
794-
mma(src.a, inv(dst.a), dst.a, inv(src.a)),
795-
};
796-
797-
case SkBlendMode::kPlus: return {
798-
p->min(p->add(src.r, dst.r), p->splat(1.0f)),
799-
p->min(p->add(src.g, dst.g), p->splat(1.0f)),
800-
p->min(p->add(src.b, dst.b), p->splat(1.0f)),
801-
p->min(p->add(src.a, dst.a), p->splat(1.0f)),
802-
};
803-
804-
case SkBlendMode::kModulate: return {
805-
p->mul(src.r, dst.r),
806-
p->mul(src.g, dst.g),
807-
p->mul(src.b, dst.b),
808-
p->mul(src.a, dst.a),
809-
};
810-
811-
case SkBlendMode::kScreen: return {
803+
case SkBlendMode::kSrcATop:
804+
return apply_rgba([&](auto s, auto d) {
805+
return mma(s, dst.a, d, inv(src.a));
806+
});
807+
808+
case SkBlendMode::kXor:
809+
return apply_rgba([&](auto s, auto d) {
810+
return mma(s, inv(dst.a), d, inv(src.a));
811+
});
812+
813+
case SkBlendMode::kPlus:
814+
return apply_rgba([&](auto s, auto d) {
815+
return min(add(s, d), splat(1.0f));
816+
});
817+
818+
case SkBlendMode::kModulate:
819+
return apply_rgba([&](auto s, auto d) {
820+
return mul(s, d);
821+
});
822+
823+
case SkBlendMode::kScreen:
812824
// (s+d)-(s*d) gave us trouble with our "r,g,b <= after blending" asserts.
813825
// It's kind of plausible that s + (d - sd) keeps more precision?
814-
p->add(src.r, p->sub(dst.r, p->mul(src.r, dst.r))),
815-
p->add(src.g, p->sub(dst.g, p->mul(src.g, dst.g))),
816-
p->add(src.b, p->sub(dst.b, p->mul(src.b, dst.b))),
817-
p->add(src.a, p->sub(dst.a, p->mul(src.a, dst.a))),
818-
};
826+
return apply_rgba([&](auto s, auto d) {
827+
return add(s, sub(d, mul(s, d)));
828+
});
829+
830+
case SkBlendMode::kDarken:
831+
return apply_rgb_srcover_a([&](auto s, auto d) {
832+
return add(s, sub(d, max(mul(s, dst.a),
833+
mul(d, src.a))));
834+
});
835+
836+
case SkBlendMode::kLighten:
837+
return apply_rgb_srcover_a([&](auto s, auto d) {
838+
return add(s, sub(d, min(mul(s, dst.a),
839+
mul(d, src.a))));
840+
});
841+
842+
case SkBlendMode::kDifference:
843+
return apply_rgb_srcover_a([&](auto s, auto d) {
844+
return add(s, sub(d, two(min(mul(s, dst.a),
845+
mul(d, src.a)))));
846+
});
847+
848+
case SkBlendMode::kExclusion:
849+
return apply_rgb_srcover_a([&](auto s, auto d) {
850+
return add(s, sub(d, two(mul(s, d))));
851+
});
852+
853+
case SkBlendMode::kColorBurn:
854+
return apply_rgb_srcover_a([&](auto s, auto d) {
855+
auto mn = min(dst.a,
856+
div(mul(sub(dst.a, d), src.a), s)),
857+
burn = mad(src.a, sub(dst.a, mn), mma(s, inv(dst.a), d, inv(src.a)));
858+
return select(eq(d, dst.a), mad(s, inv(dst.a), d),
859+
select(eq(s, splat(0.0f)), mul(d, inv(src.a)), burn));
860+
});
861+
862+
case SkBlendMode::kColorDodge:
863+
return apply_rgb_srcover_a([&](auto s, auto d) {
864+
auto tmp = mad(src.a, min(dst.a,
865+
div(mul(d, src.a), sub(src.a, s))),
866+
mma(s, inv(dst.a), d, inv(src.a)));
867+
return select(eq(d, splat(0.0f)), mul(s, inv(dst.a)),
868+
select(eq(s, src.a), mad(d, inv(src.a), s), tmp));
869+
});
870+
871+
case SkBlendMode::kHardLight:
872+
return apply_rgb_srcover_a([&](auto s, auto d) {
873+
return add(mma(s, inv(dst.a), d, inv(src.a)),
874+
select(lte(two(s), src.a),
875+
two(mul(s, d)),
876+
sub(mul(src.a, dst.a), two(mul(sub(dst.a, d), sub(src.a, s))))));
877+
});
878+
879+
case SkBlendMode::kOverlay:
880+
return apply_rgb_srcover_a([&](auto s, auto d) {
881+
return add(mma(s, inv(dst.a), d, inv(src.a)),
882+
select(lte(two(d), dst.a),
883+
two(mul(s, d)),
884+
sub(mul(src.a, dst.a), two(mul(sub(dst.a, d), sub(src.a, s))))));
885+
});
886+
887+
case SkBlendMode::kMultiply:
888+
return apply_rgba([&](auto s, auto d) {
889+
return add(mma(s, inv(dst.a), d, inv(src.a)), mul(s, d));
890+
});
891+
892+
case SkBlendMode::kSoftLight:
893+
return apply_rgb_srcover_a([&](auto s, auto d) {
894+
auto m = select(gt(dst.a, splat(0.0f)), div(d, dst.a), splat(0.0f)),
895+
s2 = two(s),
896+
m4 = two(two(m));
897+
898+
// The logic forks three ways:
899+
// 1. dark src?
900+
// 2. light src, dark dst?
901+
// 3. light src, light dst?
902+
903+
// Used in case 1
904+
auto darkSrc = mul(d, mad(sub(s2, src.a), inv(m), src.a)),
905+
// Used in case 2
906+
darkDst = mad(mad(m4, m4, m4), sub(m, splat(1.0f)), mul(splat(7.0f), m)),
907+
// Used in case 3.
908+
liteDst = sub(sqrt(m), m),
909+
// Used in 2 or 3?
910+
liteSrc = mad(mul(dst.a, sub(s2, src.a)),
911+
select(lte(two(two(d)), dst.a), darkDst, liteDst),
912+
mul(d, src.a));
913+
return mad(s, inv(dst.a), mad(d,
914+
inv(src.a),
915+
select(lte(s2, src.a), darkSrc, liteSrc)));
916+
917+
918+
});
819919
}
820920
}
821921

src/shaders/SkComposeShader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ skvm::Color SkShader_Blend::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y
142142
(dst = as_SB(fDst)->program(p, x,y, ctm,localM, q, cs, uniforms, alloc)) &&
143143
(src = as_SB(fSrc)->program(p, x,y, ctm,localM, q, cs, uniforms, alloc)))
144144
{
145-
return skvm::BlendModeProgram(p, fMode, src, dst);
145+
return p->blend(fMode, src, dst);
146146
}
147147
return {};
148148
}

0 commit comments

Comments
 (0)