support skvm fallback for single color filtering

with unit test

Change-Id: I7f0e30435bf4e054fe7436daaadb3512936a58ac
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/367237
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index d9ad7b5..3d7a22e 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -102,13 +102,29 @@
     SkStageRec rec = {
         &pipeline, &alloc, kRGBA_F32_SkColorType, dstCS, dummyPaint, nullptr, matrixProvider
     };
-    as_CFB(this)->onAppendStages(rec, color.fA == 1);
 
-    SkPMColor4f dst;
-    SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
-    pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
-    pipeline.run(0,0, 1,1);
-    return dst.unpremul();
+    if (as_CFB(this)->onAppendStages(rec, color.fA == 1)) {
+        SkPMColor4f dst;
+        SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
+        pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
+        pipeline.run(0,0, 1,1);
+        return dst.unpremul();
+    }
+
+    // This filter doesn't support SkRasterPipeline... try skvm.
+    skvm::Builder b;
+    skvm::Uniforms uni(b.uniform(), 4);
+    if (skvm::Color filtered =
+            as_CFB(this)->program(&b, b.uniformColor(color, &uni), dstCS, &uni, &alloc)) {
+
+        b.store({skvm::PixelFormat::FLOAT, 32,32,32,32, 0,32,64,96},
+                b.varying<SkColor4f>(), unpremul(filtered));
+        b.done().eval(1, uni.buf.data(), &color);  // tell SkVM to skip JIT?
+        return color;
+    }
+
+    SkASSERT(false);
+    return SkColor4f{0,0,0,0};
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index 90b45fa..a36f03f 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -382,3 +382,22 @@
         thread.join();
     }
 }
+
+DEF_TEST(SkRuntimeColorFilterSingleColor, r) {
+    // Test runtime colorfilters support filterColor4f().
+    auto [effect, err] = SkRuntimeEffect::Make(SkString{
+            "uniform shader input;  half4 main() { half4 c = sample(input); return c*c; }"});
+    REPORTER_ASSERT(r, effect);
+    REPORTER_ASSERT(r, err.isEmpty());
+
+    sk_sp<SkColorFilter> input = nullptr;
+    sk_sp<SkColorFilter> cf = effect->makeColorFilter(SkData::MakeEmpty(), &input, 1);
+    REPORTER_ASSERT(r, cf);
+
+    SkColor4f c = cf->filterColor4f({0.25, 0.5, 0.75, 1.0},
+                                    sk_srgb_singleton(), sk_srgb_singleton());
+    REPORTER_ASSERT(r, c.fR == 0.0625f);
+    REPORTER_ASSERT(r, c.fG == 0.25f);
+    REPORTER_ASSERT(r, c.fB == 0.5625f);
+    REPORTER_ASSERT(r, c.fA == 1.0f);
+}