draw atlas: using skvm

Bug=skia:12225

Change-Id: I1b6816e234cbaa49035bcedfeff894a8d2c31133
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/434680
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/core/SkDraw_atlas.cpp b/src/core/SkDraw_atlas.cpp
index 069a300..8ead762 100644
--- a/src/core/SkDraw_atlas.cpp
+++ b/src/core/SkDraw_atlas.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "include/core/SkColorFilter.h"
+#include "include/core/SkMatrix.h"
 #include "include/core/SkRSXform.h"
 #include "src/core/SkBlendModePriv.h"
 #include "src/core/SkColorSpacePriv.h"
@@ -16,10 +17,11 @@
 #include "src/core/SkRasterClip.h"
 #include "src/core/SkRasterPipeline.h"
 #include "src/core/SkScan.h"
-#include "src/shaders/SkShaderBase.h"
-
-#include "include/core/SkMatrix.h"
 #include "src/core/SkScan.h"
+#include "src/core/SkVM.h"
+#include "src/core/SkVMBlitter.h"
+#include "src/shaders/SkComposeShader.h"
+#include "src/shaders/SkShaderBase.h"
 
 static void fill_rect(const SkMatrix& ctm, const SkRasterClip& rc,
                       const SkRect& r, SkBlitter* blitter, SkPath* scratchPath) {
@@ -46,6 +48,44 @@
     ctx->rgba[3] = SkScalarRoundToInt(rgba[3]*255); ctx->a = rgba[3];
 }
 
+extern bool gUseSkVMBlitter;
+
+class UpdatableColorShader : public SkShaderBase {
+public:
+    explicit UpdatableColorShader(SkColorSpace* cs)
+        : fSteps{sk_srgb_singleton(), kUnpremul_SkAlphaType, cs, kUnpremul_SkAlphaType} {}
+    skvm::Color onProgram(
+            skvm::Builder* builder, skvm::Coord device, skvm::Coord local, skvm::Color paint,
+            const SkMatrixProvider& provider, const SkMatrix* localM, const SkColorInfo& dst,
+            skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
+        skvm::Uniform color = uniforms->pushPtr(fValues);
+        skvm::F32 r = builder->arrayF(color, 0);
+        skvm::F32 g = builder->arrayF(color, 1);
+        skvm::F32 b = builder->arrayF(color, 2);
+        skvm::F32 a = builder->arrayF(color, 3);
+
+        return {r, g, b, a};
+    }
+
+    void updateColor(SkColor c) const {
+        SkColor4f c4 = SkColor4f::FromColor(c);
+        fSteps.apply(c4.vec());
+        auto cp4 = c4.premul();
+        fValues[0] = cp4.fR;
+        fValues[1] = cp4.fG;
+        fValues[2] = cp4.fB;
+        fValues[3] = cp4.fA;
+    }
+
+private:
+    // For serialization.  This will never be called.
+    Factory getFactory() const override { return nullptr; }
+    const char* getTypeName() const override { return nullptr; }
+
+    SkColorSpaceXformSteps fSteps;
+    mutable float fValues[4];
+};
+
 void SkDraw::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect textures[],
                        const SkColor colors[], int count, SkBlendMode bmode,
                        const SkSamplingOptions& sampling, const SkPaint& paint) {
@@ -54,13 +94,45 @@
         return;
     }
 
+    SkSTArenaAlloc<256> alloc;
+
     SkPaint p(paint);
     p.setAntiAlias(false);  // we never respect this for drawAtlas(or drawVertices)
     p.setStyle(SkPaint::kFill_Style);
     p.setShader(nullptr);
     p.setMaskFilter(nullptr);
 
-    SkSTArenaAlloc<256> alloc;
+    if (gUseSkVMBlitter) {
+        auto updateShader = as_SB(atlasShader)->updatableShader(&alloc);
+        UpdatableColorShader* colorShader = nullptr;
+        SkShaderBase* shader = nullptr;
+        if (colors) {
+            colorShader = alloc.make<UpdatableColorShader>(fDst.colorSpace());
+            shader = alloc.make<SkShader_Blend>(
+                    bmode, sk_ref_sp(colorShader), sk_ref_sp(updateShader));
+        } else {
+            shader = as_SB(updateShader);
+        }
+        p.setShader(sk_ref_sp(shader));
+        if (auto blitter = SkVMBlitter::Make(fDst, p,*fMatrixProvider, &alloc, fRC->clipShader())) {
+            SkPath scratchPath;
+            for (int i = 0; i < count; ++i) {
+                if (colorShader) {
+                    colorShader->updateColor(colors[i]);
+                }
+
+                SkMatrix mx;
+                mx.setRSXform(xform[i]);
+                mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
+                mx.postConcat(fMatrixProvider->localToDevice());
+                if (updateShader->update(mx)) {
+                    fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
+                }
+            }
+            return;
+        }
+    }  // gUseSkVMBlitter
+
     SkRasterPipeline pipeline(&alloc);
     SkStageRec rec = {
         &pipeline, &alloc, fDst.colorType(), fDst.colorSpace(), p, nullptr, *fMatrixProvider
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index 3f948d7..d126df0 100755
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -741,7 +741,8 @@
         return {};
     }
     auto [upper, upperInv] = access->level();
-    if (!sampling.useCubic) {
+    // If we are using a coordShader, then we can't make guesses about the state of the matrix.
+    if (!sampling.useCubic && !coordShader) {
         // TODO: can tweak_sampling sometimes for cubic too when B=0
         if (matrices.localToDeviceHitsPixelCenters()) {
             sampling = tweak_sampling(sampling, upperInv);