tweak SkVMBlitter for paints with no shader

As written today we push two sets of the paint color uniforms (4 floats
each set, 8 total): the blitter pushes one unpremul set itself to pass
to shaders that would like to use them, and when there's no shader, we
synthesize an Color4Shader using the paint color that ends up pushing
the other set, this time premul.

When the paint color is opaque there's no difference between these two
sets of uniforms, and when not, well, it's just a few cheap *hoisted*
multiplies to go from that first unpremul set to premul.  So no real
pressing need to push those premul values at all.

This CL adds a new SkShaderBase subclass PaintColorShader used only for
that case where we're synthesizing a shader from the paint color, and
just does what I've described, `return premul(paint);`.

I really only did this because I've been poking around in the debugger
looking for some other bug and noticed the duplicate values in the
uniforms array.  I expect no real-world effect from this CL except fewer
uniforms to look at in the debugger.

Change-Id: I5e1c17945ed77467c91e351f58fcf900674c4391
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/337196
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
diff --git a/src/core/SkVMBlitter.cpp b/src/core/SkVMBlitter.cpp
index cdae32a..ba0a9c0 100644
--- a/src/core/SkVMBlitter.cpp
+++ b/src/core/SkVMBlitter.cpp
@@ -459,6 +459,30 @@
         }
     };
 
+    // This is similar to using SkShaders::Color(paint.getColor4f(), nullptr),
+    // but uses the blitter-provided paint color uniforms instead of pushing its own.
+    struct PaintColorShader : public SkShaderBase {
+        explicit PaintColorShader(bool isOpaque) : fIsOpaque(isOpaque) {}
+
+        const bool fIsOpaque;
+
+        // Only created here temporarily... never serialized.
+        Factory      getFactory() const override { return nullptr; }
+        const char* getTypeName() const override { return "PaintColorShader"; }
+
+        bool isOpaque() const override { return fIsOpaque; }
+
+        skvm::Color onProgram(skvm::Builder*,
+                              skvm::Coord, skvm::Coord, skvm::Color paint,
+                              const SkMatrixProvider&, const SkMatrix*,
+                              SkFilterQuality, const SkColorInfo&,
+                              skvm::Uniforms*, SkArenaAlloc*) const override {
+            // Incoming `paint` is unpremul in the destination color space,
+            // so we just need to premul it.
+            return premul(paint);
+        }
+    };
+
     static Params effective_params(const SkPixmap& device,
                                    const SkPixmap* sprite,
                                    SkPaint paint,
@@ -480,7 +504,7 @@
         // but if there is a shader, it's modulated by the paint alpha.
         sk_sp<SkShader> shader = paint.refShader();
         if (!shader) {
-            shader = SkShaders::Color(paint.getColor4f(), nullptr);
+            shader = sk_make_sp<PaintColorShader>(paint.getColor4f().isOpaque());
         } else if (paint.getAlphaf() < 1.0f) {
             shader = sk_make_sp<SkColorFilterShader>(std::move(shader),
                                                      paint.getAlphaf(),