/*
 * Copyright 2019 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/private/SkImageInfoPriv.h"
#include "include/private/SkMacros.h"
#include "src/core/SkArenaAlloc.h"
#include "src/core/SkBlendModePriv.h"
#include "src/core/SkBlenderBase.h"
#include "src/core/SkColorFilterBase.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkCoreBlitters.h"
#include "src/core/SkLRUCache.h"
#include "src/core/SkMatrixProvider.h"
#include "src/core/SkOpts.h"
#include "src/core/SkPaintPriv.h"
#include "src/core/SkVM.h"
#include "src/core/SkVMBlitter.h"
#include "src/shaders/SkColorFilterShader.h"

#include <cinttypes>

namespace {

    // Uniforms set by the Blitter itself,
    // rather than by the Shader, which follow this struct in the skvm::Uniforms buffer.
    struct BlitterUniforms {
        int       right;  // First device x + blit run length n, used to get device x coordinate.
        int       y;      // Device y coordinate.
    };
    static_assert(SkIsAlign4(sizeof(BlitterUniforms)), "");
    static constexpr int kBlitterUniformsCount = sizeof(BlitterUniforms) / 4;

    static skvm::Coord device_coord(skvm::Builder* p, skvm::Uniforms* uniforms) {
        skvm::I32 dx = p->uniform32(uniforms->base, offsetof(BlitterUniforms, right))
                     - p->index(),
                  dy = p->uniform32(uniforms->base, offsetof(BlitterUniforms, y));
        return {
            to_F32(dx) + 0.5f,
            to_F32(dy) + 0.5f,
        };
    }

    struct NoopColorFilter : public SkColorFilterBase {
        skvm::Color onProgram(skvm::Builder*, skvm::Color c,
                              const SkColorInfo&, skvm::Uniforms*, SkArenaAlloc*) const override {
            return c;
        }

        bool onAppendStages(const SkStageRec&, bool) const override { return true; }

        // Only created here, should never be flattened / unflattened.
        Factory getFactory() const override { return nullptr; }
        const char* getTypeName() const override { return "NoopColorFilter"; }
    };

    struct SpriteShader : public SkShaderBase {
        explicit SpriteShader(SkPixmap sprite) : fSprite(sprite) {}

        SkPixmap fSprite;

        // Only created here temporarily... never serialized.
        Factory      getFactory() const override { return nullptr; }
        const char* getTypeName() const override { return "SpriteShader"; }

        bool isOpaque() const override { return fSprite.isOpaque(); }

        skvm::Color onProgram(skvm::Builder* p,
                              skvm::Coord /*device*/, skvm::Coord /*local*/, skvm::Color /*paint*/,
                              const SkMatrixProvider&, const SkMatrix* /*localM*/,
                              const SkColorInfo& dst,
                              skvm::Uniforms* uniforms, SkArenaAlloc*) const override {
            const SkColorType ct = fSprite.colorType();

            skvm::PixelFormat fmt = skvm::SkColorType_to_PixelFormat(ct);

            skvm::Color c = p->load(fmt, p->arg(SkColorTypeBytesPerPixel(ct)));

            return SkColorSpaceXformSteps{fSprite, dst}.program(p, uniforms, c);
        }
    };

    struct DitherShader : public SkShaderBase {
        explicit DitherShader(sk_sp<SkShader> shader) : fShader(std::move(shader)) {}

        sk_sp<SkShader> fShader;

        // Only created here temporarily... never serialized.
        Factory      getFactory() const override { return nullptr; }
        const char* getTypeName() const override { return "DitherShader"; }

        bool isOpaque() const override { return fShader->isOpaque(); }

        skvm::Color onProgram(skvm::Builder* p,
                              skvm::Coord device, skvm::Coord local, skvm::Color paint,
                              const SkMatrixProvider& matrices, const SkMatrix* localM,
                              const SkColorInfo& dst,
                              skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
            // Run our wrapped shader.
            skvm::Color c = as_SB(fShader)->program(p, device,local, paint,
                                                    matrices,localM, dst, uniforms,alloc);
            if (!c) {
                return {};
            }

            float rate = 0.0f;
            switch (dst.colorType()) {
                case kARGB_4444_SkColorType:    rate =   1/15.0f; break;
                case   kRGB_565_SkColorType:    rate =   1/63.0f; break;
                case    kGray_8_SkColorType:
                case  kRGB_888x_SkColorType:
                case kRGBA_8888_SkColorType:
                case kBGRA_8888_SkColorType:    rate =  1/255.0f; break;
                case kRGB_101010x_SkColorType:
                case kRGBA_1010102_SkColorType:
                case kBGR_101010x_SkColorType:
                case kBGRA_1010102_SkColorType: rate = 1/1023.0f; break;

                case kUnknown_SkColorType:
                case kAlpha_8_SkColorType:
                case kRGBA_F16_SkColorType:
                case kRGBA_F16Norm_SkColorType:
                case kRGBA_F32_SkColorType:
                case kR8G8_unorm_SkColorType:
                case kA16_float_SkColorType:
                case kA16_unorm_SkColorType:
                case kR16G16_float_SkColorType:
                case kR16G16_unorm_SkColorType:
                case kR16G16B16A16_unorm_SkColorType: return c;
            }

            // See SkRasterPipeline dither stage.
            // This is 8x8 ordered dithering.  From here we'll only need dx and dx^dy.
            SkASSERT(local.x.id == device.x.id);
            SkASSERT(local.y.id == device.y.id);
            skvm::I32 X =     trunc(device.x - 0.5f),
                      Y = X ^ trunc(device.y - 0.5f);

            // If X's low bits are abc and Y's def, M is fcebda,
            // 6 bits producing all values [0,63] shuffled over an 8x8 grid.
            skvm::I32 M = shl(Y & 1, 5)
                        | shl(X & 1, 4)
                        | shl(Y & 2, 2)
                        | shl(X & 2, 1)
                        | shr(Y & 4, 1)
                        | shr(X & 4, 2);

            // Scale to [0,1) by /64, then to (-0.5,0.5) using 63/128 (~0.492) as 0.5-ε,
            // and finally scale all that by rate.  We keep dither strength strictly
            // within ±0.5 to not change exact values like 0 or 1.

            // rate could be a uniform, but since it's based on the destination SkColorType,
            // we can bake it in without hurting the cache hit rate.
            float scale = rate * (  2/128.0f),
                  bias  = rate * (-63/128.0f);
            skvm::F32 dither = to_F32(M) * scale + bias;
            c.r += dither;
            c.g += dither;
            c.b += dither;

            c.r = clamp(c.r, 0.0f, c.a);
            c.g = clamp(c.g, 0.0f, c.a);
            c.b = clamp(c.b, 0.0f, c.a);
            return c;
        }
    };

    // 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*, 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);
        }
    };
}  // namespace

bool SkVMBlitter::Key::operator==(const Key& that) const {
    return this->shader      == that.shader
        && this->clip        == that.clip
        && this->blender     == that.blender
        && this->colorSpace  == that.colorSpace
        && this->colorType   == that.colorType
        && this->alphaType   == that.alphaType
        && this->coverage    == that.coverage;
}

SkVMBlitter::Key SkVMBlitter::Key::withCoverage(Coverage c) const {
    Key k = *this;
    k.coverage = SkToU8(c);
    return k;
}

SkVMBlitter::Params SkVMBlitter::Params::withCoverage(Coverage c) const {
    Params p = *this;
    p.coverage = c;
    return p;
}

SkVMBlitter::Params SkVMBlitter::EffectiveParams(const SkPixmap& device,
                                                 const SkPixmap* sprite,
                                                 SkPaint paint,
                                                 const SkMatrixProvider& matrices,
                                                 sk_sp<SkShader> clip) {
    // Sprites take priority over any shader.  (There's rarely one set, and it's meaningless.)
    if (sprite) {
        paint.setShader(sk_make_sp<SpriteShader>(*sprite));
    }

    // Normal blitters will have already folded color filters into their shader,
    // but we may still need to do that here for SpriteShaders.
    if (paint.getColorFilter()) {
        SkPaintPriv::RemoveColorFilter(&paint, device.colorSpace());
    }
    SkASSERT(!paint.getColorFilter());

    // If there's no explicit shader, the paint color is the shader,
    // but if there is a shader, it's modulated by the paint alpha.
    sk_sp<SkShader> shader = paint.refShader();
    if (!shader) {
        shader = sk_make_sp<PaintColorShader>(paint.getColor4f().isOpaque());
    } else if (paint.getAlphaf() < 1.0f) {
        shader = sk_make_sp<SkColorFilterShader>(std::move(shader),
                                                 paint.getAlphaf(),
                                                 sk_make_sp<NoopColorFilter>());
    }

    // Add dither to the end of the shader pipeline if requested and needed.
    if (paint.isDither() && !as_SB(shader)->isConstant()) {
        shader = sk_make_sp<DitherShader>(std::move(shader));
    }

    // Add the blender.
    sk_sp<SkBlender> blender = paint.refBlender();
    if (!blender) {
        blender = SkBlender::Mode(SkBlendMode::kSrcOver);
    }

    // The most common blend mode is SrcOver, and it can be strength-reduced
    // _greatly_ to Src mode when the shader is opaque.
    //
    // In general all the information we use to make decisions here need to
    // be reflected in Params and Key to make program caching sound, and it
    // might appear that shader->isOpaque() is a property of the shader's
    // uniforms than its fundamental program structure and so unsafe to use.
    //
    // Opacity is such a powerful property that SkShaderBase::program()
    // forces opacity for any shader subclass that claims isOpaque(), so
    // the opaque bit is strongly guaranteed to be part of the program and
    // not just a property of the uniforms.  The shader program hash includes
    // this information, making it safe to use anywhere in the blitter codegen.
    if (as_BB(blender)->asBlendMode() == SkBlendMode::kSrcOver && shader->isOpaque()) {
        blender = SkBlender::Mode(SkBlendMode::kSrc);
    }

    SkColor4f paintColor = paint.getColor4f();
    SkColorSpaceXformSteps{sk_srgb_singleton(), kUnpremul_SkAlphaType,
                           device.colorSpace(), kUnpremul_SkAlphaType}
            .apply(paintColor.vec());

    return {
        std::move(shader),
        std::move(clip),
        std::move(blender),
        { device.colorType(), device.alphaType(), device.refColorSpace() },
        Coverage::Full,  // Placeholder... withCoverage() will change as needed.
        paintColor,
        matrices,
    };
}

skvm::Color SkVMBlitter::DstColor(skvm::Builder* p, const Params& params) {
    skvm::PixelFormat dstFormat = skvm::SkColorType_to_PixelFormat(params.dst.colorType());
    skvm::Ptr dst_ptr = p->arg(SkColorTypeBytesPerPixel(params.dst.colorType()));
    return p->load(dstFormat, dst_ptr);
}

void SkVMBlitter::BuildProgram(skvm::Builder* p, const Params& params,
                               skvm::Uniforms* uniforms, SkArenaAlloc* alloc) {
    // First two arguments are always uniforms and the destination buffer.
    uniforms->base    = p->uniform();
    skvm::Ptr dst_ptr = p->arg(SkColorTypeBytesPerPixel(params.dst.colorType()));
    // A SpriteShader (in this file) may next use one argument as its varying source.
    // Subsequent arguments depend on params.coverage:
    //    - Full:      (no more arguments)
    //    - Mask3D:    mul varying, add varying, 8-bit coverage varying
    //    - MaskA8:    8-bit coverage varying
    //    - MaskLCD16: 565 coverage varying
    //    - UniformF:  float coverage uniform

    skvm::Coord device = device_coord(p, uniforms);
    skvm::Color paint = p->uniformColor(params.paint, uniforms);

    // See note about arguments above: a SpriteShader will call p->arg() once during program().
    skvm::Color src = as_SB(params.shader)->program(p, device, /*local=*/device, paint,
                                                    params.matrices, /*localM=*/nullptr,
                                                    params.dst, uniforms, alloc);
    SkASSERT(src);
    if (params.coverage == Coverage::Mask3D) {
        skvm::F32 M = from_unorm(8, p->load8(p->varying<uint8_t>())),
                  A = from_unorm(8, p->load8(p->varying<uint8_t>()));

        src.r = min(src.r * M + A, src.a);
        src.g = min(src.g * M + A, src.a);
        src.b = min(src.b * M + A, src.a);
    }

    // If we can determine this we can skip a fair bit of clamping!
    bool src_in_gamut = false;

    // Normalized premul formats can surprisingly represent some out-of-gamut
    // values (e.g. r=0xff, a=0xee fits in unorm8 but r = 1.07), but most code
    // working with normalized premul colors is not prepared to handle r,g,b > a.
    // So we clamp the shader to gamut here before blending and coverage.
    //
    // In addition, GL clamps all its color channels to limits of the format just
    // before the blend step (~here).  To match that auto-clamp, we clamp alpha to
    // [0,1] too, just in case someone gave us an out of range alpha.
    if (!src_in_gamut
            && params.dst.alphaType() == kPremul_SkAlphaType
            && SkColorTypeIsNormalized(params.dst.colorType())) {
        src.a = clamp(src.a, 0.0f,  1.0f);
        src.r = clamp(src.r, 0.0f, src.a);
        src.g = clamp(src.g, 0.0f, src.a);
        src.b = clamp(src.b, 0.0f, src.a);
        src_in_gamut = true;
    }

    // Load the destination color.
    skvm::PixelFormat dstFormat = skvm::SkColorType_to_PixelFormat(params.dst.colorType());
    skvm::Color dst = p->load(dstFormat, dst_ptr);
    if (params.dst.isOpaque()) {
        // When a destination is known opaque, we may assume it both starts and stays fully
        // opaque, ignoring any math that disagrees.  This sometimes trims a little work.
        dst.a = p->splat(1.0f);
    } else if (params.dst.alphaType() == kUnpremul_SkAlphaType) {
        // All our blending works in terms of premul.
        dst = premul(dst);
    }

    // Load coverage.
    skvm::Color cov;
    switch (params.coverage) {
        case Coverage::Full:
            cov.r = cov.g = cov.b = cov.a = p->splat(1.0f);
            break;

        case Coverage::UniformF:
            cov.r = cov.g = cov.b = cov.a = p->uniformF(p->uniform(), 0);
            break;

        case Coverage::Mask3D:
        case Coverage::MaskA8:
            cov.r = cov.g = cov.b = cov.a = from_unorm(8, p->load8(p->varying<uint8_t>()));
            break;

        case Coverage::MaskLCD16: {
            skvm::PixelFormat fmt = skvm::SkColorType_to_PixelFormat(kRGB_565_SkColorType);
            cov = p->load(fmt, p->varying<uint16_t>());
            cov.a = select(src.a < dst.a, min(cov.r, min(cov.g, cov.b)),
                           max(cov.r, max(cov.g, cov.b)));
        } break;
    }
    if (params.clip) {
        skvm::Color clip = as_SB(params.clip)->program(p, device, /*local=*/device, paint,
                                                       params.matrices, /*localM=*/nullptr,
                                                       params.dst, uniforms, alloc);
        SkAssertResult(clip);
        cov.r *= clip.a;  // We use the alpha channel of clip for all four.
        cov.g *= clip.a;
        cov.b *= clip.a;
        cov.a *= clip.a;
    }

    const SkBlenderBase* blender = as_BB(params.blender);
    const auto as_blendmode = blender->asBlendMode();

    // The math for some blend modes lets us fold coverage into src before the blend, which is
    // simpler than the canonical post-blend lerp().
    bool applyPostBlendCoverage = true;
    if (as_blendmode &&
        SkBlendMode_ShouldPreScaleCoverage(as_blendmode.value(),
                                           params.coverage == Coverage::MaskLCD16)) {
        applyPostBlendCoverage = false;
        src.r *= cov.r;
        src.g *= cov.g;
        src.b *= cov.b;
        src.a *= cov.a;
    }

    // Apply our blend function to the computed color.
    src = blender->program(p, src, dst, params.dst, uniforms, alloc);

    if (applyPostBlendCoverage) {
        src.r = lerp(dst.r, src.r, cov.r);
        src.g = lerp(dst.g, src.g, cov.g);
        src.b = lerp(dst.b, src.b, cov.b);
        src.a = lerp(dst.a, src.a, cov.a);
    }

    if (params.dst.isOpaque()) {
        // (See the note above when loading the destination color.)
        src.a = p->splat(1.0f);
    } else if (params.dst.alphaType() == kUnpremul_SkAlphaType) {
        src = unpremul(src);
    }

    // Clamp to fit destination color format if needed.
    if (as_blendmode && src_in_gamut) {
        // An in-gamut src blended with an in-gamut dst should stay in gamut.
        // Being in-gamut implies all channels are in [0,1], so no need to clamp.
        // We allow one ulp error above 1.0f, and about that much (~1.2e-7) below 0.
        skvm::F32 lo = pun_to_F32(p->splat(0xb400'0000)),
                  hi = pun_to_F32(p->splat(0x3f80'0001));
        assert_true(src.r == clamp(src.r, lo, hi), src.r);
        assert_true(src.g == clamp(src.g, lo, hi), src.g);
        assert_true(src.b == clamp(src.b, lo, hi), src.b);
        assert_true(src.a == clamp(src.a, lo, hi), src.a);
    } else if (SkColorTypeIsNormalized(params.dst.colorType())) {
        src = clamp01(src);
    }

    // Write it out!
    store(dstFormat, dst_ptr, src);
}

// If BuildProgram() can't build this program, CacheKey() sets *ok to false.
SkVMBlitter::Key SkVMBlitter::CacheKey(
        const Params& params, skvm::Uniforms* uniforms, SkArenaAlloc* alloc, bool* ok) {
    // Take care to match buildProgram()'s reuse of the paint color uniforms.
    skvm::Uniform r = uniforms->pushF(params.paint.fR),
                  g = uniforms->pushF(params.paint.fG),
                  b = uniforms->pushF(params.paint.fB),
                  a = uniforms->pushF(params.paint.fA);

    auto hash_shader = [&](skvm::Builder& p, const sk_sp<SkShader>& shader,
                           skvm::Color* outColor) {
        const SkShaderBase* sb = as_SB(shader);

        skvm::Coord device = device_coord(&p, uniforms);
        skvm::Color paint = {
            p.uniformF(r),
            p.uniformF(g),
            p.uniformF(b),
            p.uniformF(a),
        };

        uint64_t hash = 0;
        *outColor = sb->program(&p, device, /*local=*/device, paint, params.matrices,
                /*localM=*/nullptr, params.dst, uniforms, alloc);
        if (*outColor) {
            hash = p.hash();
            // p.hash() folds in all instructions to produce r,g,b,a but does not know
            // precisely which value we'll treat as which channel.  Imagine the shader
            // called std::swap(*r,*b)... it draws differently, but p.hash() is unchanged.
            // We'll fold the hash of their IDs in order to disambiguate.
            const skvm::Val outputs[] = {
                outColor->r.id,
                outColor->g.id,
                outColor->b.id,
                outColor->a.id
            };
            hash ^= SkOpts::hash(outputs, sizeof(outputs));
        } else {
            *ok = false;
        }
        return hash;
    };

    // Use this builder for shader, clip and blender, so that color objects that pass
    // from one to the other all 'make sense' -- i.e. have the same builder and/or have
    // meaningful values for the hash.
    //
    // Question: better if we just pass in mock uniform colors, so we don't need to
    //           explicitly use the output color from one stage as input to another?
    //
    skvm::Builder p;

    // Calculate a hash for the color shader.
    SkASSERT(params.shader);
    skvm::Color src;
    uint64_t shaderHash = hash_shader(p, params.shader, &src);

    // Calculate a hash for the clip shader, if one exists.
    uint64_t clipHash = 0;
    if (params.clip) {
        skvm::Color cov;
        clipHash = hash_shader(p, params.clip, &cov);
        if (clipHash == 0) {
            clipHash = 1;
        }
    }

    // Calculate a hash for the blender.
    uint64_t blendHash = 0;
    if (auto bm = as_BB(params.blender)->asBlendMode()) {
        blendHash = static_cast<uint8_t>(bm.value());
    } else if (*ok) {
        const SkBlenderBase* blender = as_BB(params.blender);

        skvm::Color dst = DstColor(&p, params);
        skvm::Color outColor = blender->program(&p, src, dst, params.dst, uniforms, alloc);
        if (outColor) {
            blendHash = p.hash();
            // Like in `hash_shader` above, we must fold the color component IDs into our hash.
            const skvm::Val outputs[] = {
                outColor.r.id,
                outColor.g.id,
                outColor.b.id,
                outColor.a.id
            };
            blendHash ^= SkOpts::hash(outputs, sizeof(outputs));
        } else {
            *ok = false;
        }
        if (blendHash == 0) {
            blendHash = 1;
        }
    }

    return {
        shaderHash,
        clipHash,
        blendHash,
        params.dst.colorSpace() ? params.dst.colorSpace()->hash() : 0,
        SkToU8(params.dst.colorType()),
        SkToU8(params.dst.alphaType()),
        SkToU8(params.coverage),
    };
}

SkVMBlitter::SkVMBlitter(const SkPixmap& device,
                         const SkPaint& paint,
                         const SkPixmap* sprite,
                         SkIPoint spriteOffset,
                         const SkMatrixProvider& matrices,
                         sk_sp<SkShader> clip,
                         bool* ok)
        : fDevice(device), fSprite(sprite ? *sprite : SkPixmap{})
        , fSpriteOffset(spriteOffset)
        , fUniforms(skvm::Ptr{0}
        , kBlitterUniformsCount)
        , fParams(EffectiveParams(device, sprite, paint, matrices, std::move(clip)))
        , fKey(CacheKey(fParams, &fUniforms, &fAlloc, ok)) {}

SkVMBlitter::~SkVMBlitter() {
    if (SkLRUCache<Key, skvm::Program>* cache = TryAcquireProgramCache()) {
        auto cache_program = [&](skvm::Program&& program, Coverage coverage) {
            if (!program.empty()) {
                cache->insert_or_update(fKey.withCoverage(coverage), std::move(program));
            }
        };
        cache_program(std::move(fBlitH),         Coverage::Full);
        cache_program(std::move(fBlitAntiH),     Coverage::UniformF);
        cache_program(std::move(fBlitMaskA8),    Coverage::MaskA8);
        cache_program(std::move(fBlitMask3D),    Coverage::Mask3D);
        cache_program(std::move(fBlitMaskLCD16), Coverage::MaskLCD16);

        ReleaseProgramCache();
    }
}

SkLRUCache<SkVMBlitter::Key, skvm::Program>* SkVMBlitter::TryAcquireProgramCache() {
#if 1 && defined(SKVM_JIT)
    thread_local static SkLRUCache<Key, skvm::Program> cache{64};
    return &cache;
#else
    // iOS in particular does not support thread_local until iOS 9.0.
        // On the other hand, we'll never be able to JIT there anyway.
        // It's probably fine to not cache any interpreted programs, anywhere.
        return nullptr;
#endif
}

SkString SkVMBlitter::DebugName(const Key& key) {
    return SkStringPrintf("Shader-%" PRIx64 "_Clip-%" PRIx64 "_Blender-%" PRIx64
                          "_CS-%" PRIx64 "_CT-%d_AT-%d_Cov-%d",
                          key.shader,
                          key.clip,
                          key.blender,
                          key.colorSpace,
                          key.colorType,
                          key.alphaType,
                          key.coverage);
}

void SkVMBlitter::ReleaseProgramCache() {}

skvm::Program SkVMBlitter::buildProgram(Coverage coverage) {
    Key key = fKey.withCoverage(coverage);
    {
        skvm::Program p;
        if (SkLRUCache<Key, skvm::Program>* cache = TryAcquireProgramCache()) {
            if (skvm::Program* found = cache->find(key)) {
                p = std::move(*found);
            }
            ReleaseProgramCache();
        }
        if (!p.empty()) {
            return p;
        }
    }
    // We don't really _need_ to rebuild fUniforms here.
    // It's just more natural to have effects unconditionally emit them,
    // and more natural to rebuild fUniforms than to emit them into a temporary buffer.
    // fUniforms should reuse the exact same memory, so this is very cheap.
    SkDEBUGCODE(size_t prev = fUniforms.buf.size();)
    fUniforms.buf.resize(kBlitterUniformsCount);
    skvm::Builder builder;
    BuildProgram(&builder, fParams.withCoverage(coverage), &fUniforms, &fAlloc);
    SkASSERTF(fUniforms.buf.size() == prev,
              "%zu, prev was %zu", fUniforms.buf.size(), prev);

    skvm::Program program = builder.done(DebugName(key).c_str());
    if (false) {
        static std::atomic<int> missed{0},
                total{0};
        if (!program.hasJIT()) {
            SkDebugf("\ncouldn't JIT %s\n", DebugName(key).c_str());
            builder.dump();
            program.dump();

            missed++;
        }
        if (0 == total++) {
            atexit([]{ SkDebugf("SkVMBlitter compiled %d programs, %d without JIT.\n",
                                total.load(), missed.load()); });
        }
    }
    return program;
}

void SkVMBlitter::updateUniforms(int right, int y) {
    BlitterUniforms uniforms{right, y};
    memcpy(fUniforms.buf.data(), &uniforms, sizeof(BlitterUniforms));
}

const void* SkVMBlitter::isSprite(int x, int y) const {
    if (fSprite.colorType() != kUnknown_SkColorType) {
        return fSprite.addr(x - fSpriteOffset.x(),
                            y - fSpriteOffset.y());
    }
    return nullptr;
}

void SkVMBlitter::blitH(int x, int y, int w) {
    if (fBlitH.empty()) {
        fBlitH = this->buildProgram(Coverage::Full);
    }
    this->updateUniforms(x+w, y);
    if (const void* sprite = this->isSprite(x,y)) {
        fBlitH.eval(w, fUniforms.buf.data(), fDevice.addr(x,y), sprite);
    } else {
        fBlitH.eval(w, fUniforms.buf.data(), fDevice.addr(x,y));
    }
}

void SkVMBlitter::blitAntiH(int x, int y, const SkAlpha cov[], const int16_t runs[]) {
    if (fBlitAntiH.empty()) {
        fBlitAntiH = this->buildProgram(Coverage::UniformF);
    }
    for (int16_t run = *runs; run > 0; run = *runs) {
        this->updateUniforms(x+run, y);
        const float covF = *cov * (1/255.0f);
        if (const void* sprite = this->isSprite(x,y)) {
            fBlitAntiH.eval(run, fUniforms.buf.data(), fDevice.addr(x,y), sprite, &covF);
        } else {
            fBlitAntiH.eval(run, fUniforms.buf.data(), fDevice.addr(x,y), &covF);
        }
        x    += run;
        runs += run;
        cov  += run;
    }
}

void SkVMBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
    if (mask.fFormat == SkMask::kBW_Format) {
        return SkBlitter::blitMask(mask, clip);
    }

    const skvm::Program* program = nullptr;
    switch (mask.fFormat) {
        default: SkUNREACHABLE;     // ARGB and SDF masks shouldn't make it here.

        case SkMask::k3D_Format:
            if (fBlitMask3D.empty()) {
                fBlitMask3D = this->buildProgram(Coverage::Mask3D);
            }
            program = &fBlitMask3D;
            break;

        case SkMask::kA8_Format:
            if (fBlitMaskA8.empty()) {
                fBlitMaskA8 = this->buildProgram(Coverage::MaskA8);
            }
            program = &fBlitMaskA8;
            break;

        case SkMask::kLCD16_Format:
            if (fBlitMaskLCD16.empty()) {
                fBlitMaskLCD16 = this->buildProgram(Coverage::MaskLCD16);
            }
            program = &fBlitMaskLCD16;
            break;
    }

    SkASSERT(program);
    if (program) {
        for (int y = clip.top(); y < clip.bottom(); y++) {
             int x = clip.left(),
                 w = clip.width();
            void* dptr =        fDevice.writable_addr(x,y);
            auto  mptr = (const uint8_t*)mask.getAddr(x,y);
            this->updateUniforms(x+w,y);

            if (program == &fBlitMask3D) {
                size_t plane = mask.computeImageSize();
                if (const void* sprite = this->isSprite(x,y)) {
                    program->eval(w, fUniforms.buf.data(), dptr, sprite, mptr + 1*plane
                                                                       , mptr + 2*plane
                                                                       , mptr + 0*plane);
                } else {
                    program->eval(w, fUniforms.buf.data(), dptr, mptr + 1*plane
                                                               , mptr + 2*plane
                                                               , mptr + 0*plane);
                }
            } else {
                if (const void* sprite = this->isSprite(x,y)) {
                    program->eval(w, fUniforms.buf.data(), dptr, sprite, mptr);
                } else {
                    program->eval(w, fUniforms.buf.data(), dptr, mptr);
                }
            }
        }
    }
}

SkVMBlitter* SkVMBlitter::Make(const SkPixmap& device,
                               const SkPaint& paint,
                               const SkMatrixProvider& matrices,
                               SkArenaAlloc* alloc,
                               sk_sp<SkShader> clip) {
    bool ok = true;
    SkVMBlitter* blitter = alloc->make<SkVMBlitter>(
            device, paint, /*sprite=*/nullptr, SkIPoint{0,0}, matrices, std::move(clip), &ok);
    return ok ? blitter : nullptr;
}

SkVMBlitter* SkVMBlitter::Make(const SkPixmap& device,
                               const SkPaint& paint,
                               const SkPixmap& sprite,
                               int left, int top,
                               SkArenaAlloc* alloc,
                               sk_sp<SkShader> clip) {
    if (paint.getMaskFilter()) {
        // TODO: SkVM support for mask filters?  definitely possible!
        return nullptr;
    }
    bool ok = true;
    auto blitter = alloc->make<SkVMBlitter>(
            device, paint, &sprite, SkIPoint{left,top},
            SkSimpleMatrixProvider{SkMatrix{}}, std::move(clip), &ok);
    return ok ? blitter : nullptr;
}
