@@ -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
731731bool 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
0 commit comments