static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
                              const CopyParams& copyParams) {
    SkASSERT(!subset || !subset->isEmpty());
    GrContext* context = inputTexture->getContext();
    SkASSERT(context);

    GrPixelConfig config = GrMakePixelConfigUncompressed(inputTexture->config());

    sk_sp<GrDrawContext> copyDC = context->makeDrawContextWithFallback(SkBackingFit::kExact,
                                                                       copyParams.fWidth,
                                                                       copyParams.fHeight,
                                                                       config, nullptr);
    if (!copyDC) {
        return nullptr;
    }

    GrPaint paint;
    paint.setGammaCorrect(true);

    SkScalar sx SK_INIT_TO_AVOID_WARNING;
    SkScalar sy SK_INIT_TO_AVOID_WARNING;
    if (subset) {
        sx = 1.f / inputTexture->width();
        sy = 1.f / inputTexture->height();
    }

    if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
        (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
        SkRect domain;
        domain.fLeft = (subset->fLeft + 0.5f) * sx;
        domain.fTop = (subset->fTop + 0.5f)* sy;
        domain.fRight = (subset->fRight - 0.5f) * sx;
        domain.fBottom = (subset->fBottom - 0.5f) * sy;
        // This would cause us to read values from outside the subset. Surely, the caller knows
        // better!
        SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
        paint.addColorFragmentProcessor(
            GrTextureDomainEffect::Make(inputTexture, nullptr, SkMatrix::I(), domain,
                                        GrTextureDomain::kClamp_Mode,
                                        copyParams.fFilter));
    } else {
        GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
        paint.addColorTextureProcessor(inputTexture, nullptr, SkMatrix::I(), params);
    }
    paint.setPorterDuffXPFactory(SkBlendMode::kSrc);

    SkRect localRect;
    if (subset) {
        localRect = SkRect::Make(*subset);
        localRect.fLeft *= sx;
        localRect.fTop *= sy;
        localRect.fRight *= sx;
        localRect.fBottom *= sy;
    } else {
        localRect = SkRect::MakeWH(1.f, 1.f);
    }

    SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
    copyDC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
    return copyDC->asTexture().release();
}