Initial texture data is never flipped when uploaded.

The first bytes of the data always refer to the pixel accessed by texture coord (0, 0).

Change-Id: I708702d90f35b3bc896a48c3c3fd6a0be73f505a
Reviewed-on: https://skia-review.googlesource.com/112261
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index b1f9c0b..defd063 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1188,6 +1188,7 @@
       sources = [
         "tools/gpu/GrContextFactory.cpp",
         "tools/gpu/GrTest.cpp",
+        "tools/gpu/ProxyUtils.cpp",
         "tools/gpu/TestContext.cpp",
         "tools/gpu/atlastext/GLTestAtlasTextRenderer.cpp",
         "tools/gpu/gl/GLTestContext.cpp",
diff --git a/gm/flippity.cpp b/gm/flippity.cpp
index 554b4d1..d730ed5 100644
--- a/gm/flippity.cpp
+++ b/gm/flippity.cpp
@@ -13,7 +13,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrContextPriv.h"
-#include "GrProxyProvider.h"
+#include "ProxyUtils.h"
 #include "SkImage_Gpu.h"
 
 static const int kNumMatrices = 6;
@@ -85,20 +85,15 @@
     return image->makeTextureImage(context, nullptr);
 }
 
-static SkColor swap_red_and_blue(SkColor c) {
-    return SkColorSetRGB(SkColorGetB(c), SkColorGetG(c), SkColorGetR(c));
-}
-
 // Create an image with each corner marked w/ "LL", "LR", etc., with the origin either bottom-left
 // or top-left.
 static sk_sp<SkImage> make_reference_image(GrContext* context,
                                            const SkTArray<sk_sp<SkImage>>& labels,
                                            bool bottomLeftOrigin) {
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
     SkASSERT(kNumLabels == labels.count());
 
-    SkImageInfo ii = SkImageInfo::Make(kImageSize, kImageSize,
-                                       kN32_SkColorType, kOpaque_SkAlphaType);
+    SkImageInfo ii =
+            SkImageInfo::Make(kImageSize, kImageSize, kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
     SkBitmap bm;
     bm.allocPixels(ii);
     SkCanvas canvas(bm);
@@ -110,26 +105,11 @@
                          0.0 != kPoints[i].fY ? kPoints[i].fY-kLabelSize-kInset : kInset);
     }
 
-    GrSurfaceDesc desc;
-    desc.fWidth = kImageSize;
-    desc.fHeight = kImageSize;
-    desc.fConfig = kRGBA_8888_GrPixelConfig;
-
     auto origin = bottomLeftOrigin ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
 
-    if (kN32_SkColorType == kBGRA_8888_SkColorType) {
-        // We're playing a game here and uploading N32 data into an RGB dest. We might have
-        // to swap red & blue to compensate.
-        for (int y = 0; y < bm.height(); ++y) {
-            uint32_t *sl = bm.getAddr32(0, y);
-            for (int x = 0; x < bm.width(); ++x) {
-                sl[x] = swap_red_and_blue(sl[x]);
-            }
-        }
-    }
-
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(desc, origin, SkBudgeted::kYes,
-                                                                    bm.getPixels(), bm.rowBytes());
+    auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, false, kImageSize, kImageSize,
+                                                       bm.colorType(), origin, bm.getPixels(),
+                                                       bm.rowBytes());
     if (!proxy) {
         return nullptr;
     }
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index 716bbc3..b6d7cba 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -94,9 +94,8 @@
         desc.fConfig = SkImageInfo2GrPixelConfig(fBmp.info(), *context->caps());
         SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
 
-        sk_sp<GrTextureProxy> proxy =
-                proxyProvider->createTextureProxy(desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kYes,
-                                                  fBmp.getPixels(), fBmp.rowBytes());
+        sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
+                desc, SkBudgeted::kYes, fBmp.getPixels(), fBmp.rowBytes());
         if (!proxy) {
             return;
         }
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index ee710ee..74c11a9 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -93,9 +93,8 @@
             desc.fConfig = SkImageInfo2GrPixelConfig(fBmp[i].info(), *context->caps());
             SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
 
-            proxy[i] = proxyProvider->createTextureProxy(desc, kTopLeft_GrSurfaceOrigin,
-                                                         SkBudgeted::kYes, fBmp[i].getPixels(),
-                                                         fBmp[i].rowBytes());
+            proxy[i] = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
+                                                         fBmp[i].getPixels(), fBmp[i].rowBytes());
             if (!proxy[i]) {
                 return;
             }
@@ -220,9 +219,8 @@
             desc.fConfig = SkImageInfo2GrPixelConfig(fBmp[index].info(), *context->caps());
             SkASSERT(kUnknown_GrPixelConfig != desc.fConfig);
 
-            proxy[i] = proxyProvider->createTextureProxy(desc, kTopLeft_GrSurfaceOrigin,
-                                                         SkBudgeted::kYes, fBmp[index].getPixels(),
-                                                         fBmp[index].rowBytes());
+            proxy[i] = proxyProvider->createTextureProxy(
+                    desc, SkBudgeted::kYes, fBmp[index].getPixels(), fBmp[index].rowBytes());
             if (!proxy[i]) {
                 return;
             }
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index 950a78a..e8bb87c 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -71,9 +71,13 @@
     friend class GrProxyProvider; // for ctors
     friend class GrTextureProxyPriv;
 
-    // Deferred version
+    // Deferred version - when constructed with data the origin is always kTopLeft.
+    GrTextureProxy(const GrSurfaceDesc& srcDesc, GrMipMapped, SkBackingFit, SkBudgeted,
+                   const void* srcData, size_t srcRowBytes, uint32_t flags);
+
+    // Deferred version - no data.
     GrTextureProxy(const GrSurfaceDesc& srcDesc, GrSurfaceOrigin, GrMipMapped, SkBackingFit,
-                   SkBudgeted, const void* srcData, size_t srcRowBytes, uint32_t flags);
+                   SkBudgeted, uint32_t flags);
 
     // Lazy-callback version
     // There are two main use cases for lazily-instantiated proxies:
diff --git a/src/effects/GrCircleBlurFragmentProcessor.cpp b/src/effects/GrCircleBlurFragmentProcessor.cpp
index c774540..b345f27 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.cpp
+++ b/src/effects/GrCircleBlurFragmentProcessor.cpp
@@ -226,8 +226,8 @@
                     create_circle_profile(sigma * scale, circleR * scale, kProfileTextureWidth));
         }
 
-        blurProfile = proxyProvider->createTextureProxy(texDesc, kTopLeft_GrSurfaceOrigin,
-                                                        SkBudgeted::kYes, profile.get(), 0);
+        blurProfile =
+                proxyProvider->createTextureProxy(texDesc, SkBudgeted::kYes, profile.get(), 0);
         if (!blurProfile) {
             return nullptr;
         }
diff --git a/src/effects/GrCircleBlurFragmentProcessor.fp b/src/effects/GrCircleBlurFragmentProcessor.fp
index 2294e0f..ef4c289 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.fp
+++ b/src/effects/GrCircleBlurFragmentProcessor.fp
@@ -249,7 +249,7 @@
             }
 
             blurProfile = proxyProvider->createTextureProxy(
-                    texDesc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kYes, profile.get(), 0);
+                    texDesc, SkBudgeted::kYes, profile.get(), 0);
             if (!blurProfile) {
                 return nullptr;
             }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 5e15472..9a9c2d5 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -72,8 +72,7 @@
 }
 
 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted,
-                                      GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
-                                      int mipLevelCount) {
+                                      const GrMipLevel texels[], int mipLevelCount) {
     GR_CREATE_TRACE_MARKER_CONTEXT("GrGpu", "createTexture", fContext);
     GrSurfaceDesc desc = origDesc;
 
@@ -94,8 +93,7 @@
     }
 
     this->handleDirtyContext();
-    sk_sp<GrTexture> tex =
-            this->onCreateTexture(desc, budgeted, texelsOrigin, texels, mipLevelCount);
+    sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount);
     if (tex) {
         if (!this->caps()->reuseScratchTextures() && !isRT) {
             tex->resourcePriv().removeScratchKey();
@@ -111,7 +109,7 @@
 }
 
 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted) {
-    return this->createTexture(desc, budgeted, kTopLeft_GrSurfaceOrigin, nullptr, 0);
+    return this->createTexture(desc, budgeted, nullptr, 0);
 }
 
 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index e7e4ac0..786fb31 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -93,20 +93,18 @@
      * pixel configs can be used as render targets. Support for configs as textures
      * or render targets can be checked using GrCaps.
      *
-     * @param desc         describes the texture to be created.
-     * @param budgeted     does this texture count against the resource cache budget?
-     * @param texelsOrigin origin of the texel data to be uploaded. Ignored if there is
-     *                     no initial texel data.
-     * @param texels       array of mipmap levels containing texel data to load.
-     *                     Each level begins with full-size palette data for paletted textures.
-     *                     It contains width*height texels. If there is only one
-     *                     element and it contains nullptr fPixels, texture data is
-     *                     uninitialized.
-     * @param mipLevelCount the number of levels in 'texels'
-     * @return    The texture object if successful, otherwise nullptr.
+     * @param desc           describes the texture to be created.
+     * @param budgeted       does this texture count against the resource cache budget?
+     * @param texels         array of mipmap levels containing texel data to load.
+     *                       Each level begins with full-size palette data for paletted textures.
+     *                       It contains width*height texels. If there is only one
+     *                       element and it contains nullptr fPixels, texture data is
+     *                       uninitialized.
+     * @param mipLevelCount  the number of levels in 'texels'
+     * @return  The texture object if successful, otherwise nullptr.
      */
-    sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, GrSurfaceOrigin texelsOrigin,
-                                   const GrMipLevel texels[], int mipLevelCount);
+    sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, const GrMipLevel texels[],
+                                   int mipLevelCount);
 
     /**
      * Simplified createTexture() interface for when there is no initial texel data to upload.
@@ -546,7 +544,6 @@
     // Texture size and sample size will have already been validated in base class before
     // onCreateTexture is called.
     virtual sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted,
-                                             GrSurfaceOrigin texelsOrigin,
                                              const GrMipLevel texels[], int mipLevelCount) = 0;
 
     virtual sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership) = 0;
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index 5b91dd1..536cd13 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -176,7 +176,6 @@
 }
 
 sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(const GrSurfaceDesc& desc,
-                                                          GrSurfaceOrigin origin,
                                                           SkBudgeted budgeted, const void* srcData,
                                                           size_t rowBytes) {
     ASSERT_SINGLE_OWNER
@@ -188,21 +187,20 @@
     if (srcData) {
         GrMipLevel mipLevel = { srcData, rowBytes };
 
-        sk_sp<GrTexture> tex = fResourceProvider->createTexture(
-                desc, budgeted, SkBackingFit::kExact, origin, mipLevel);
+        sk_sp<GrTexture> tex =
+                fResourceProvider->createTexture(desc, budgeted, SkBackingFit::kExact, mipLevel);
         if (!tex) {
             return nullptr;
         }
 
-        return this->createWrapped(std::move(tex), origin);
+        return this->createWrapped(std::move(tex), kTopLeft_GrSurfaceOrigin);
     }
 
-    return this->createProxy(desc, origin, SkBackingFit::kExact, budgeted);
+    return this->createProxy(desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kExact, budgeted);
 }
 
 sk_sp<GrTextureProxy> GrProxyProvider::createTextureProxy(sk_sp<SkImage> srcImage,
                                                           GrSurfaceFlags flags,
-                                                          GrSurfaceOrigin origin,
                                                           int sampleCnt,
                                                           SkBudgeted budgeted,
                                                           SkBackingFit fit) {
@@ -245,7 +243,7 @@
     desc.fConfig = config;
 
     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
-            [desc, origin, budgeted, srcImage, fit](GrResourceProvider* resourceProvider) {
+            [desc, budgeted, srcImage, fit](GrResourceProvider* resourceProvider) {
                 if (!resourceProvider) {
                     // Nothing to clean up here. Once the proxy (and thus lambda) is deleted the ref
                     // on srcImage will be released.
@@ -255,9 +253,9 @@
                 SkAssertResult(srcImage->peekPixels(&pixMap));
                 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() };
 
-                return resourceProvider->createTexture(desc, budgeted, fit, origin, mipLevel);
+                return resourceProvider->createTexture(desc, budgeted, fit, mipLevel);
             },
-            desc, origin, GrMipMapped::kNo, renderTargetFlags, fit, budgeted);
+            desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, renderTargetFlags, fit, budgeted);
 
     if (fResourceProvider) {
         // In order to reuse code we always create a lazy proxy. When we aren't in DDL mode however
@@ -320,9 +318,8 @@
     GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *this->caps());
 
     if (0 == mipmaps->countLevels()) {
-        return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, kTopLeft_GrSurfaceOrigin,
-                                        1, SkBudgeted::kYes, SkBackingFit::kExact);
-
+        return this->createTextureProxy(baseLevel, kNone_GrSurfaceFlags, 1, SkBudgeted::kYes,
+                                        SkBackingFit::kExact);
     }
 
     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
@@ -350,8 +347,7 @@
                     SkASSERT(texels[i].fPixels);
                 }
 
-                return resourceProvider->createTexture(desc, SkBudgeted::kYes,
-                                                       kTopLeft_GrSurfaceOrigin, texels.get(),
+                return resourceProvider->createTexture(desc, SkBudgeted::kYes, texels.get(),
                                                        mipLevelCount, mipColorMode);
             },
             desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes, SkBackingFit::kExact,
@@ -400,7 +396,7 @@
     }
 
     return sk_sp<GrTextureProxy>(
-            new GrTextureProxy(copyDesc, origin, mipMapped, fit, budgeted, nullptr, 0, flags));
+            new GrTextureProxy(copyDesc, origin, mipMapped, fit, budgeted, flags));
 }
 
 sk_sp<GrTextureProxy> GrProxyProvider::createWrappedTextureProxy(
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index 20d546f..12ff10c 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -73,8 +73,8 @@
      * DDL TODO: need to refine ownership semantics of 'srcData' if we're in completely
      * deferred mode
      */
-    sk_sp<GrTextureProxy> createTextureProxy(const GrSurfaceDesc&, GrSurfaceOrigin, SkBudgeted,
-                                             const void* srcData, size_t rowBytes);
+    sk_sp<GrTextureProxy> createTextureProxy(const GrSurfaceDesc&, SkBudgeted, const void* srcData,
+                                             size_t rowBytes);
 
     /*
      * Create an un-mipmapped texture proxy with data. The SkImage must be a raster backend image.
@@ -83,7 +83,6 @@
      */
     sk_sp<GrTextureProxy> createTextureProxy(sk_sp<SkImage> srcImage,
                                              GrSurfaceFlags flags,
-                                             GrSurfaceOrigin origin,
                                              int sampleCnt,
                                              SkBudgeted budgeted,
                                              SkBackingFit fit);
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index f81eea3..df848e8 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -62,7 +62,6 @@
 }
 
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                                   GrSurfaceOrigin texelsOrigin,
                                                    const GrMipLevel texels[], int mipLevelCount,
                                                    SkDestinationSurfaceColorMode mipColorMode) {
     ASSERT_SINGLE_OWNER
@@ -78,7 +77,7 @@
         return nullptr;
     }
 
-    sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texelsOrigin, texels, mipLevelCount));
+    sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texels, mipLevelCount));
     if (tex) {
         tex->texturePriv().setMipColorMode(mipColorMode);
     }
@@ -109,7 +108,6 @@
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
                                                    SkBudgeted budgeted,
                                                    SkBackingFit fit,
-                                                   GrSurfaceOrigin mipLevelOrigin,
                                                    const GrMipLevel& mipLevel) {
     ASSERT_SINGLE_OWNER
 
@@ -133,8 +131,8 @@
     if (make_info(desc.fWidth, desc.fHeight, desc.fConfig, &srcInfo)) {
         // DDL TODO: remove this use of createInstantiatedProxy and convert it to a testing-only
         // method.
-        sk_sp<GrTextureProxy> proxy =
-                proxyProvider->createInstantiatedProxy(desc, mipLevelOrigin, fit, budgeted);
+        sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(
+                desc, kTopLeft_GrSurfaceOrigin, fit, budgeted);
         if (proxy) {
             // We use an ephemeral surface context to do the write pixels. Here it isn't clear what
             // color space to tag it with. That's ok because GrSurfaceContext::writePixels doesn't
@@ -155,7 +153,7 @@
         }
     }
 
-    return fGpu->createTexture(desc, budgeted, mipLevelOrigin, &mipLevel, 1);
+    return fGpu->createTexture(desc, budgeted, &mipLevel, 1);
 }
 
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 083f5a9..68bcf45 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -68,13 +68,12 @@
      */
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, uint32_t flags = 0);
 
-    sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, GrSurfaceOrigin texelsOrigin,
-                                   const GrMipLevel texels[], int mipLevelCount,
-                                   SkDestinationSurfaceColorMode mipColorMode);
+    sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, const GrMipLevel texels[],
+                                   int mipLevelCount, SkDestinationSurfaceColorMode mipColorMode);
 
     // Create a potentially loose fit texture with the provided data
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, SkBackingFit,
-                                   GrSurfaceOrigin mipLevelOrigin, const GrMipLevel&);
+                                   const GrMipLevel&);
 
     ///////////////////////////////////////////////////////////////////////////
     // Wrapped Backend Surfaces
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index b8132e8..c78e998 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -144,7 +144,7 @@
             texels[i].fRowBytes = 0;
         }
 
-        surface = resourceProvider->createTexture(desc, fBudgeted, fOrigin, texels.get(), mipCount,
+        surface = resourceProvider->createTexture(desc, fBudgeted, texels.get(), mipCount,
                                                   SkDestinationSurfaceColorMode::kLegacy);
         if (surface) {
             SkASSERT(surface->asTexture());
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index cfeb34c..a19a803 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -14,17 +14,26 @@
 #include "GrProxyProvider.h"
 #include "GrTexturePriv.h"
 
-// Deferred version
-GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, GrSurfaceOrigin origin,
-                               GrMipMapped mipMapped, SkBackingFit fit, SkBudgeted budgeted,
-                               const void* srcData, size_t /*rowBytes*/, uint32_t flags)
-        : INHERITED(srcDesc, origin, fit, budgeted, flags)
+// Deferred version - with data
+GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, GrMipMapped mipMapped,
+                               SkBackingFit fit, SkBudgeted budgeted, const void* srcData,
+                               size_t /*rowBytes*/, uint32_t flags)
+        : INHERITED(srcDesc, kTopLeft_GrSurfaceOrigin, fit, budgeted, flags)
         , fMipMapped(mipMapped)
         , fProxyProvider(nullptr)
         , fDeferredUploader(nullptr) {
     SkASSERT(!srcData);  // currently handled in Make()
 }
 
+// Deferred version - no data
+GrTextureProxy::GrTextureProxy(const GrSurfaceDesc& srcDesc, GrSurfaceOrigin origin,
+                               GrMipMapped mipMapped, SkBackingFit fit, SkBudgeted budgeted,
+                               uint32_t flags)
+        : INHERITED(srcDesc, origin, fit, budgeted, flags)
+        , fMipMapped(mipMapped)
+        , fProxyProvider(nullptr)
+        , fDeferredUploader(nullptr) {}
+
 // Lazy-callback version
 GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback, LazyInstantiationType lazyType,
                                const GrSurfaceDesc& desc, GrSurfaceOrigin origin,
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index c36867d..e753b8d 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -26,7 +26,7 @@
                                                        uint32_t flags)
         : GrSurfaceProxy(desc, origin, fit, budgeted, flags)
         // for now textures w/ data are always wrapped
-        , GrTextureProxy(desc, origin, mipMapped, fit, budgeted, nullptr, 0, flags)
+        , GrTextureProxy(desc, origin, mipMapped, fit, budgeted, flags)
         , GrRenderTargetProxy(caps, desc, origin, fit, budgeted, flags) {}
 
 // Lazy-callback version
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index bd66dba..b79d4a7 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -105,7 +105,6 @@
 
         auto proxyProvider = ctx->contextPriv().proxyProvider();
         yuvTextureProxies[i] = proxyProvider->createTextureProxy(yuvImage, kNone_GrSurfaceFlags,
-                                                                 kTopLeft_GrSurfaceOrigin,
                                                                  1, SkBudgeted::kYes, fit);
     }
 
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 58df7c5..4701483 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -88,9 +88,8 @@
                                                                        : kNever_SkCopyPixelsMode;
     sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, cpyMode);
 
-    return proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags,
-                                             kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
-                                             SkBackingFit::kExact);
+    return proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
+                                             SkBudgeted::kYes, SkBackingFit::kExact);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -200,9 +199,8 @@
         proxy = proxyProvider->findOrCreateProxyByUniqueKey(originalKey, kTopLeft_GrSurfaceOrigin);
     }
     if (!proxy) {
-        proxy = proxyProvider->createTextureProxy(std::move(srcImage), kNone_GrSurfaceFlags,
-                                                  kTopLeft_GrSurfaceOrigin, 1, SkBudgeted::kYes,
-                                                  fit);
+        proxy = proxyProvider->createTextureProxy(std::move(srcImage), kNone_GrSurfaceFlags, 1,
+                                                  SkBudgeted::kYes, fit);
         if (proxy && originalKey.isValid()) {
             proxyProvider->assignUniqueKeyToProxy(originalKey, proxy.get());
         }
diff --git a/src/gpu/effects/GrConfigConversionEffect.fp b/src/gpu/effects/GrConfigConversionEffect.fp
index d5e9eae..762093e 100644
--- a/src/gpu/effects/GrConfigConversionEffect.fp
+++ b/src/gpu/effects/GrConfigConversionEffect.fp
@@ -61,7 +61,7 @@
         GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
 
         sk_sp<GrTextureProxy> dataProxy = proxyProvider->createTextureProxy(
-                desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kYes, data, 0);
+                desc, SkBudgeted::kYes, data, 0);
         if (!dataProxy) {
             return false;
         }
diff --git a/src/gpu/effects/GrConfigConversionEffect.h b/src/gpu/effects/GrConfigConversionEffect.h
index 0b5a205..ca3cd85 100644
--- a/src/gpu/effects/GrConfigConversionEffect.h
+++ b/src/gpu/effects/GrConfigConversionEffect.h
@@ -64,8 +64,8 @@
 
         GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
 
-        sk_sp<GrTextureProxy> dataProxy = proxyProvider->createTextureProxy(
-                desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kYes, data, 0);
+        sk_sp<GrTextureProxy> dataProxy =
+                proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, data, 0);
         if (!dataProxy) {
             return false;
         }
diff --git a/src/gpu/effects/GrRectBlurEffect.fp b/src/gpu/effects/GrRectBlurEffect.fp
index 7057a8e..3f55017 100644
--- a/src/gpu/effects/GrRectBlurEffect.fp
+++ b/src/gpu/effects/GrRectBlurEffect.fp
@@ -68,8 +68,8 @@
             }
 
             blurProfile = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags,
-                                                            kTopLeft_GrSurfaceOrigin, 1,
-                                                            SkBudgeted::kYes, SkBackingFit::kExact);
+                                                            1, SkBudgeted::kYes,
+                                                            SkBackingFit::kExact);
             if (!blurProfile) {
                 return nullptr;
             }
diff --git a/src/gpu/effects/GrRectBlurEffect.h b/src/gpu/effects/GrRectBlurEffect.h
index b6b8a02..44f54bb 100644
--- a/src/gpu/effects/GrRectBlurEffect.h
+++ b/src/gpu/effects/GrRectBlurEffect.h
@@ -47,9 +47,9 @@
                 return nullptr;
             }
 
-            blurProfile = proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags,
-                                                            kTopLeft_GrSurfaceOrigin, 1,
-                                                            SkBudgeted::kYes, SkBackingFit::kExact);
+            blurProfile =
+                    proxyProvider->createTextureProxy(std::move(image), kNone_GrSurfaceFlags, 1,
+                                                      SkBudgeted::kYes, SkBackingFit::kExact);
             if (!blurProfile) {
                 return nullptr;
             }
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index ea7be0e..2a1d403 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1413,7 +1413,6 @@
 
 sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
                                           SkBudgeted budgeted,
-                                          GrSurfaceOrigin texelsOrigin,
                                           const GrMipLevel texels[],
                                           int mipLevelCount) {
     // We fail if the MSAA was requested and is not available.
@@ -1445,8 +1444,8 @@
     idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
     GrMipMapsStatus mipMapsStatus;
     GrGLTexture::TexParams initialTexParams;
-    if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams,
-                                 texelsOrigin, texels, mipLevelCount, &mipMapsStatus)) {
+    if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams, texels,
+                                 mipLevelCount, &mipMapsStatus)) {
         return return_null_texture();
     }
 
@@ -1632,8 +1631,7 @@
 }
 
 bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, bool renderTarget,
-                                GrGLTexture::TexParams* initialTexParams,
-                                GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
+                                GrGLTexture::TexParams* initialTexParams, const GrMipLevel texels[],
                                 int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
     info->fID = 0;
     info->fTarget = GR_GL_TEXTURE_2D;
@@ -1657,9 +1655,9 @@
         set_initial_texture_params(this->glInterface(), *info, initialTexParams);
     }
 
-    if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, texelsOrigin, info->fTarget,
-                             kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
-                             texels, mipLevelCount, mipMapsStatus)) {
+    if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, kTopLeft_GrSurfaceOrigin,
+                             info->fTarget, kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight,
+                             desc.fConfig, texels, mipLevelCount, mipMapsStatus)) {
         GL_CALL(DeleteTextures(1, &(info->fID)));
         return false;
     }
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 6b19399..81c15f0 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -184,8 +184,7 @@
     void xferBarrier(GrRenderTarget*, GrXferBarrierType) override;
 
     sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                     GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
-                                     int mipLevelCount) override;
+                                     const GrMipLevel texels[], int mipLevelCount) override;
 
     GrBuffer* onCreateBuffer(size_t size, GrBufferType intendedType, GrAccessPattern,
                              const void* data) override;
@@ -208,9 +207,8 @@
     // The texture is populated with |texels|, if it exists.
     // The texture parameters are cached in |initialTexParams|.
     bool createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, bool renderTarget,
-                           GrGLTexture::TexParams* initialTexParams, GrSurfaceOrigin texelsOrigin,
-                           const GrMipLevel texels[], int mipLevelCount,
-                           GrMipMapsStatus* mipMapsStatus);
+                           GrGLTexture::TexParams* initialTexParams, const GrMipLevel texels[],
+                           int mipLevelCount, GrMipMapsStatus* mipMapsStatus);
 
     bool onIsACopyNeededForTextureParams(GrTextureProxy*, const GrSamplerState&,
                                          GrTextureProducer::CopyParams*,
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index 05371b4..9341472 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -65,8 +65,7 @@
 }
 
 sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                            GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
-                                            int mipLevelCount) {
+                                            const GrMipLevel texels[], int mipLevelCount) {
     GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid
                                                       : GrMipMapsStatus::kNotAllocated;
     GrMockTextureInfo info;
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 14cbd79..e44cc36 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -55,8 +55,8 @@
 
     void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
 
-    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted, GrSurfaceOrigin texelsOrigin,
-                                     const GrMipLevel texels[], int mipLevelCount) override;
+    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted, const GrMipLevel[],
+                                     int mipLevelCount) override;
 
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership) override {
         return nullptr;
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index fd190e2..5bc9c06 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -82,8 +82,7 @@
     void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
 
     sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                     GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
-                                     int mipLevelCount) override;
+                                     const GrMipLevel texels[], int mipLevelCount) override;
 
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership) override {
         return nullptr;
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index c8952e0..149e562 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -107,8 +107,7 @@
 }
 
 sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                           GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
-                                           int mipLevelCount) {
+                                           const GrMipLevel texels[], int mipLevelCount) {
     int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
 
     if (!fMtlCaps->isConfigTexturable(desc.fConfig)) {
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 3a81eed..1af5a3f 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -763,8 +763,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                          GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
-                                          int mipLevelCount) {
+                                          const GrMipLevel texels[], int mipLevelCount) {
     bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
 
     VkFormat pixelFormat;
@@ -825,8 +824,8 @@
 
     auto colorType = GrPixelConfigToColorType(desc.fConfig);
     if (mipLevelCount) {
-        if (!this->uploadTexDataOptimal(tex.get(), texelsOrigin, 0, 0, desc.fWidth, desc.fHeight,
-                                        colorType, texels, mipLevelCount)) {
+        if (!this->uploadTexDataOptimal(tex.get(), kTopLeft_GrSurfaceOrigin, 0, 0, desc.fWidth,
+                                        desc.fHeight, colorType, texels, mipLevelCount)) {
             tex->unref();
             return nullptr;
         }
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 7616fcc..e622d57 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -164,8 +164,7 @@
 
     void destroyResources();
 
-    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                     GrSurfaceOrigin texelsOrigin, const GrMipLevel texels[],
+    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted, const GrMipLevel[],
                                      int mipLevelCount) override;
 
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership) override;
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 0ba3f03..86f89db 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -648,8 +648,7 @@
         if (SkImageInfoIsValid(pixmap.info(), colorMode)) {
             ATRACE_ANDROID_FRAMEWORK("Upload Texture [%ux%u]", pixmap.width(), pixmap.height());
             GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(pixmap.info(), *proxyProvider->caps());
-            proxy = proxyProvider->createTextureProxy(desc, kTopLeft_GrSurfaceOrigin,
-                                                      SkBudgeted::kYes, pixmap.addr(),
+            proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, pixmap.addr(),
                                                       pixmap.rowBytes());
         }
     }
diff --git a/tests/CopySurfaceTest.cpp b/tests/CopySurfaceTest.cpp
index b373258..9574208 100644
--- a/tests/CopySurfaceTest.cpp
+++ b/tests/CopySurfaceTest.cpp
@@ -12,26 +12,17 @@
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
 #include "GrContextPriv.h"
-#include "GrProxyProvider.h"
-#include "GrResourceProvider.h"
-#include "GrSurfaceContext.h"
-#include "GrSurfaceProxy.h"
 #include "GrTextureProxy.h"
+#include "ProxyUtils.h"
 
 #include "SkUtils.h"
 
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CopySurface, reporter, ctxInfo) {
     GrContext* context = ctxInfo.grContext();
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
     static const int kW = 10;
     static const int kH = 10;
     static const size_t kRowBytes = sizeof(uint32_t) * kW;
 
-    GrSurfaceDesc baseDesc;
-    baseDesc.fConfig = kRGBA_8888_GrPixelConfig;
-    baseDesc.fWidth = kW;
-    baseDesc.fHeight = kH;
-
     SkAutoTMalloc<uint32_t> srcPixels(kW * kH);
     for (int i = 0; i < kW * kH; ++i) {
         srcPixels.get()[i] = i;
@@ -65,19 +56,16 @@
 
     for (auto sOrigin : {kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin}) {
         for (auto dOrigin : {kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin}) {
-            for (auto sFlags: {kRenderTarget_GrSurfaceFlag, kNone_GrSurfaceFlags}) {
-                for (auto dFlags: {kRenderTarget_GrSurfaceFlag, kNone_GrSurfaceFlags}) {
+            for (auto sRT : {true, false}) {
+                for (auto dRT : {true, false}) {
                     for (auto srcRect : kSrcRects) {
                         for (auto dstPoint : kDstPoints) {
-                            GrSurfaceDesc srcDesc = baseDesc;
-                            srcDesc.fFlags = sFlags;
-                            GrSurfaceDesc dstDesc = baseDesc;
-                            dstDesc.fFlags = dFlags;
-
-                            sk_sp<GrTextureProxy> src = proxyProvider->createTextureProxy(
-                                    srcDesc, sOrigin, SkBudgeted::kNo, srcPixels.get(), kRowBytes);
-                            sk_sp<GrTextureProxy> dst = proxyProvider->createTextureProxy(
-                                    dstDesc, dOrigin, SkBudgeted::kNo, dstPixels.get(), kRowBytes);
+                            auto src = sk_gpu_test::MakeTextureProxyFromData(
+                                    context, sRT, kW, kH, ii.colorType(), sOrigin, srcPixels.get(),
+                                    kRowBytes);
+                            auto dst = sk_gpu_test::MakeTextureProxyFromData(
+                                    context, dRT, kW, kH, ii.colorType(), dOrigin, dstPixels.get(),
+                                    kRowBytes);
                             if (!src || !dst) {
                                 ERRORF(reporter,
                                        "Could not create surfaces for copy surface test.");
diff --git a/tests/FloatingPointTextureTest.cpp b/tests/FloatingPointTextureTest.cpp
index 6d2beb3..dac13a5 100644
--- a/tests/FloatingPointTextureTest.cpp
+++ b/tests/FloatingPointTextureTest.cpp
@@ -20,6 +20,7 @@
 #include "GrContextPriv.h"
 #include "GrProxyProvider.h"
 #include "GrTextureProxy.h"
+#include "ProxyUtils.h"
 #include "SkHalf.h"
 
 static const int DEV_W = 100, DEV_H = 100;
@@ -33,7 +34,6 @@
         return;
     }
 
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
     SkTDArray<T> controlPixelData, readBuffer;
     controlPixelData.setCount(arraySize);
     readBuffer.setCount(arraySize);
@@ -46,14 +46,8 @@
     }
 
     for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
-        GrSurfaceDesc desc;
-        desc.fFlags = kRenderTarget_GrSurfaceFlag;
-        desc.fWidth = DEV_W;
-        desc.fHeight = DEV_H;
-        desc.fConfig = GrColorTypeToPixelConfig(colorType, GrSRGBEncoded::kNo);
-
-        sk_sp<GrTextureProxy> fpProxy = proxyProvider->createTextureProxy(
-                desc, origin, SkBudgeted::kNo, controlPixelData.begin(), 0);
+        auto fpProxy = sk_gpu_test::MakeTextureProxyFromData(context, true, DEV_W, DEV_H, colorType,
+                                                             origin, controlPixelData.begin(), 0);
         // Floating point textures are NOT supported everywhere
         if (!fpProxy) {
             continue;
diff --git a/tests/ImageFilterCacheTest.cpp b/tests/ImageFilterCacheTest.cpp
index a2409dc..a541c1c 100644
--- a/tests/ImageFilterCacheTest.cpp
+++ b/tests/ImageFilterCacheTest.cpp
@@ -196,8 +196,8 @@
     desc.fHeight = kFullSize;
     desc.fConfig = kRGBA_8888_GrPixelConfig;
 
-    return proxyProvider->createTextureProxy(desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kYes,
-                                             srcBM.getPixels(), srcBM.rowBytes());
+    return proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, srcBM.getPixels(),
+                                             srcBM.rowBytes());
 }
 
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, ctxInfo) {
diff --git a/tests/PackedConfigsTextureTest.cpp b/tests/PackedConfigsTextureTest.cpp
index 0ac322d..b1fbc77 100644
--- a/tests/PackedConfigsTextureTest.cpp
+++ b/tests/PackedConfigsTextureTest.cpp
@@ -18,6 +18,7 @@
 #include "GrContextPriv.h"
 #include "GrProxyProvider.h"
 #include "GrTextureProxy.h"
+#include "ProxyUtils.h"
 
 static const int DEV_W = 10, DEV_H = 10;
 static const uint8_t TOL = 0x4;
@@ -95,9 +96,8 @@
     }
 }
 
-static void run_test(skiatest::Reporter* reporter, GrContext* context,
-                     int arraySize, GrPixelConfig config) {
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
+static void run_test(skiatest::Reporter* reporter, GrContext* context, int arraySize,
+                     GrColorType colorType) {
     SkTDArray<uint16_t> controlPixelData;
     // We will read back into an 8888 buffer since 565/4444 read backs aren't supported
     SkTDArray<GrColor> readBuffer;
@@ -113,14 +113,8 @@
                                                   kRGBA_8888_SkColorType, kOpaque_SkAlphaType);
 
     for (auto origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
-        GrSurfaceDesc desc;
-        desc.fFlags = kNone_GrSurfaceFlags;
-        desc.fWidth = DEV_W;
-        desc.fHeight = DEV_H;
-        desc.fConfig = config;
-
-        sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-                desc, origin, SkBudgeted::kNo, controlPixelData.begin(), 0);
+        auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, false, DEV_W, DEV_H, colorType,
+                                                           origin, controlPixelData.begin(), 0);
         SkASSERT(proxy);
 
         sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(
@@ -128,10 +122,10 @@
 
         SkAssertResult(sContext->readPixels(dstInfo, readBuffer.begin(), 0, 0, 0));
 
-        if (kRGBA_4444_GrPixelConfig == config) {
+        if (GrColorType::kABGR_4444 == colorType) {
             check_4444(reporter, controlPixelData, readBuffer);
         } else {
-            SkASSERT(kRGB_565_GrPixelConfig == config);
+            SkASSERT(GrColorType::kRGB_565 == colorType);
             check_565(reporter, controlPixelData, readBuffer);
         }
     }
@@ -140,11 +134,11 @@
 static const int CONTROL_ARRAY_SIZE = DEV_W * DEV_H;
 
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(RGBA4444TextureTest, reporter, ctxInfo) {
-    run_test(reporter, ctxInfo.grContext(), CONTROL_ARRAY_SIZE, kRGBA_4444_GrPixelConfig);
+    run_test(reporter, ctxInfo.grContext(), CONTROL_ARRAY_SIZE, GrColorType::kABGR_4444);
 }
 
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(RGB565TextureTest, reporter, ctxInfo) {
-    run_test(reporter, ctxInfo.grContext(), CONTROL_ARRAY_SIZE, kRGB_565_GrPixelConfig);
+    run_test(reporter, ctxInfo.grContext(), CONTROL_ARRAY_SIZE, GrColorType::kRGB_565);
 }
 
 #endif
diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp
index 2694bca..d435059 100644
--- a/tests/ProcessorTest.cpp
+++ b/tests/ProcessorTest.cpp
@@ -308,8 +308,7 @@
             }
         }
 
-        proxies[0] = proxyProvider->createTextureProxy(desc, kBottomLeft_GrSurfaceOrigin,
-                                                       SkBudgeted::kYes, rgbaData.get(),
+        proxies[0] = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, rgbaData.get(),
                                                        kTestTextureSize * sizeof(GrColor));
     }
 
@@ -323,8 +322,7 @@
             }
         }
 
-        proxies[1] = proxyProvider->createTextureProxy(desc, kBottomLeft_GrSurfaceOrigin,
-                                                       SkBudgeted::kYes, alphaData.get(),
+        proxies[1] = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, alphaData.get(),
                                                        kTestTextureSize);
     }
 
@@ -345,8 +343,8 @@
     desc.fHeight = height;
     desc.fConfig = kRGBA_8888_GrPixelConfig;
 
-    return proxyProvider->createTextureProxy(desc, kBottomLeft_GrSurfaceOrigin, SkBudgeted::kYes,
-                                             data.get(), width * sizeof(GrColor));
+    return proxyProvider->createTextureProxy(desc, SkBudgeted::kYes, data.get(),
+                                             width * sizeof(GrColor));
 }
 
 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp
index 34cf5bc..ccb2ced 100644
--- a/tests/ReadPixelsTest.cpp
+++ b/tests/ReadPixelsTest.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include <initializer_list>
 #include "SkCanvas.h"
 #include "SkColorData.h"
 #include "SkHalf.h"
@@ -18,10 +19,10 @@
 #include "GrContextFactory.h"
 #include "GrContextPriv.h"
 #include "GrProxyProvider.h"
+#include "ProxyUtils.h"
 #include "SkGr.h"
 #endif
 
-#include <initializer_list>
 
 static const int DEV_W = 100, DEV_H = 100;
 static const SkIRect DEV_RECT = SkIRect::MakeWH(DEV_W, DEV_H);
@@ -449,25 +450,16 @@
     }
 
     GrContext* context = ctxInfo.grContext();
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
-
     SkBitmap bmp = make_src_bitmap();
 
     // On the GPU we will also try reading back from a non-renderable texture.
     for (auto origin : {kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin}) {
-        for (auto flags : {kNone_GrSurfaceFlags, kRenderTarget_GrSurfaceFlag}) {
-            GrSurfaceDesc desc;
-            desc.fFlags = flags;
-            desc.fWidth = DEV_W;
-            desc.fHeight = DEV_H;
-            desc.fConfig = kSkia8888_GrPixelConfig;
-
-            sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-                    desc, origin, SkBudgeted::kNo, bmp.getPixels(), bmp.rowBytes());
-
+        for (auto isRT : {false, true}) {
+            sk_sp<GrTextureProxy> proxy = sk_gpu_test::MakeTextureProxyFromData(
+                    context, isRT, DEV_W, DEV_H, bmp.colorType(), origin, bmp.getPixels(),
+                    bmp.rowBytes());
             sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(
                                                                                 std::move(proxy));
-
             test_readpixels_texture(reporter, std::move(sContext));
         }
     }
diff --git a/tests/ReadWriteAlphaTest.cpp b/tests/ReadWriteAlphaTest.cpp
index f495fc2..eaad411 100644
--- a/tests/ReadWriteAlphaTest.cpp
+++ b/tests/ReadWriteAlphaTest.cpp
@@ -9,7 +9,6 @@
 
 // This test is specific to the GPU backend.
 #if SK_SUPPORT_GPU
-
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrProxyProvider.h"
@@ -17,6 +16,7 @@
 #include "GrSurfaceContext.h"
 #include "GrSurfaceProxy.h"
 #include "GrTextureProxy.h"
+#include "ProxyUtils.h"
 #include "SkCanvas.h"
 #include "SkSurface.h"
 
@@ -26,12 +26,12 @@
 
 static void validate_alpha_data(skiatest::Reporter* reporter, int w, int h, const uint8_t* actual,
                                 size_t actualRowBytes, const uint8_t* expected, SkString extraMsg,
-                                GrPixelConfig config) {
+                                GrColorType colorType) {
     for (int y = 0; y < h; ++y) {
         for (int x = 0; x < w; ++x) {
             uint8_t a = actual[y * actualRowBytes + x];
             uint8_t e = expected[y * w + x];
-            if (kRGBA_1010102_GrPixelConfig == config) {
+            if (GrColorType::kRGBA_1010102 == colorType) {
                 // This config only preserves two bits of alpha
                 a >>= 6;
                 e >>= 6;
@@ -66,8 +66,8 @@
         // We are initializing the texture with zeros here
         memset(alphaData, 0, X_SIZE * Y_SIZE);
 
-        sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-                desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kNo, alphaData, 0);
+        sk_sp<GrTextureProxy> proxy =
+                proxyProvider->createTextureProxy(desc, SkBudgeted::kNo, alphaData, 0);
         if (!proxy) {
             ERRORF(reporter, "Could not create alpha texture.");
             return;
@@ -105,7 +105,7 @@
             SkString msg;
             msg.printf("rb:%d A8", SkToU32(rowBytes));
             validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
-                                alphaData, msg, kAlpha_8_GrPixelConfig);
+                                alphaData, msg, GrColorType::kAlpha_8);
 
             // Now try writing to a single channel surface (if we could create one).
             if (surf) {
@@ -146,11 +146,14 @@
         }
     }
 
-    static const GrPixelConfig kRGBAConfigs[] {
-        kRGBA_8888_GrPixelConfig,
-        kBGRA_8888_GrPixelConfig,
-        kSRGBA_8888_GrPixelConfig,
-        kRGBA_1010102_GrPixelConfig,
+    static constexpr struct {
+        GrColorType fColorType;
+        GrSRGBEncoded fSRGBEncoded;
+    } kInfos[] = {
+            {GrColorType::kRGBA_8888, GrSRGBEncoded::kNo},
+            {GrColorType::kBGRA_8888, GrSRGBEncoded::kNo},
+            {GrColorType::kRGBA_8888, GrSRGBEncoded::kYes},
+            {GrColorType::kRGBA_1010102, GrSRGBEncoded::kNo},
     };
 
     for (int y = 0; y < Y_SIZE; ++y) {
@@ -165,14 +168,8 @@
 
     // Attempt to read back just alpha from a RGBA/BGRA texture. Once with a texture-only src and
     // once with a render target.
-    for (auto config : kRGBAConfigs) {
+    for (auto info : kInfos) {
         for (int rt = 0; rt < 2; ++rt) {
-            GrSurfaceDesc desc;
-            desc.fFlags     = rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
-            desc.fConfig    = config;
-            desc.fWidth     = X_SIZE;
-            desc.fHeight    = Y_SIZE;
-
             uint32_t rgbaData[X_SIZE * Y_SIZE];
             // Make the alpha channel of the rgba texture come from alphaData.
             for (int y = 0; y < Y_SIZE; ++y) {
@@ -182,13 +179,10 @@
             }
 
             auto origin = rt ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
-            sk_sp<GrTextureProxy> proxy =
-                    proxyProvider->createTextureProxy(desc, origin, SkBudgeted::kNo, rgbaData, 0);
+            auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, rt, X_SIZE, Y_SIZE,
+                                                               info.fColorType, info.fSRGBEncoded,
+                                                               origin, rgbaData, 0);
             if (!proxy) {
-                // We always expect to be able to create a RGBA texture
-                if (!rt  && kRGBA_8888_GrPixelConfig == desc.fConfig) {
-                    ERRORF(reporter, "Failed to create RGBA texture.");
-                }
                 continue;
             }
 
@@ -214,7 +208,7 @@
                 SkString msg;
                 msg.printf("rt:%d, rb:%d 8888", rt, SkToU32(rowBytes));
                 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
-                                    alphaData, msg, config);
+                                    alphaData, msg, info.fColorType);
             }
         }
     }
diff --git a/tests/SRGBMipMapTest.cpp b/tests/SRGBMipMapTest.cpp
index 91294de..7be4db6 100644
--- a/tests/SRGBMipMapTest.cpp
+++ b/tests/SRGBMipMapTest.cpp
@@ -131,8 +131,8 @@
     desc.fConfig = kSRGBA_8888_GrPixelConfig;
 
     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(desc, kTopLeft_GrSurfaceOrigin,
-                                                                    SkBudgeted::kNo, texData, 0);
+    sk_sp<GrTextureProxy> proxy =
+            proxyProvider->createTextureProxy(desc, SkBudgeted::kNo, texData, 0);
 
     // Create two render target contexts (L32 and S32)
     sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeSRGB();
diff --git a/tests/SpecialImageTest.cpp b/tests/SpecialImageTest.cpp
index f201fb0..8397795 100644
--- a/tests/SpecialImageTest.cpp
+++ b/tests/SpecialImageTest.cpp
@@ -238,7 +238,7 @@
         const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
 
         sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-                desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes());
+                desc, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes());
         if (!proxy) {
             return;
         }
@@ -270,8 +270,8 @@
 
     const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bm.info(), *context->caps());
 
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-            desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes());
+    sk_sp<GrTextureProxy> proxy =
+            proxyProvider->createTextureProxy(desc, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes());
     if (!proxy) {
         return;
     }
@@ -309,8 +309,8 @@
     desc.fHeight = kFullSize;
     desc.fConfig = kSkia8888_GrPixelConfig;
 
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-            desc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes());
+    sk_sp<GrTextureProxy> proxy =
+            proxyProvider->createTextureProxy(desc, SkBudgeted::kNo, bm.getPixels(), bm.rowBytes());
     if (!proxy) {
         return;
     }
diff --git a/tests/TestUtils.cpp b/tests/TestUtils.cpp
index 7878233..1b146c2 100644
--- a/tests/TestUtils.cpp
+++ b/tests/TestUtils.cpp
@@ -11,8 +11,10 @@
 
 #include "GrProxyProvider.h"
 #include "GrSurfaceContext.h"
+#include "GrSurfaceContextPriv.h"
 #include "GrSurfaceProxy.h"
 #include "GrTextureProxy.h"
+#include "ProxyUtils.h"
 
 void test_read_pixels(skiatest::Reporter* reporter,
                       GrSurfaceContext* srcContext, uint32_t expectedPixelValues[],
@@ -103,22 +105,14 @@
         }
     }
 
-    GrSurfaceDesc copySrcDesc;
-    copySrcDesc.fWidth = dstContext->width();
-    copySrcDesc.fHeight = dstContext->height();
-    copySrcDesc.fConfig = kRGBA_8888_GrPixelConfig;
-
-    for (auto flags : { kNone_GrSurfaceFlags, kRenderTarget_GrSurfaceFlag }) {
-        copySrcDesc.fFlags = flags;
-        auto origin = (kNone_GrSurfaceFlags == flags) ? kTopLeft_GrSurfaceOrigin
-                                                      : kBottomLeft_GrSurfaceOrigin;
-
-        sk_sp<GrTextureProxy> src = proxyProvider->createTextureProxy(
-                copySrcDesc, origin, SkBudgeted::kYes, pixels.get(), 0);
-
-        dstContext->copy(src.get());
-
-        test_read_pixels(reporter, dstContext, pixels.get(), testName);
+    for (auto isRT : {false, true}) {
+        for (auto origin : {kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
+            auto src = sk_gpu_test::MakeTextureProxyFromData(
+                    dstContext->surfPriv().getContext(), isRT, dstContext->width(),
+                    dstContext->height(), GrColorType::kRGBA_8888, origin, pixels.get(), 0);
+            dstContext->copy(src.get());
+            test_read_pixels(reporter, dstContext, pixels.get(), testName);
+        }
     }
 }
 
diff --git a/tests/VkUploadPixelsTests.cpp b/tests/VkUploadPixelsTests.cpp
index f2d6af3..acadf7d 100644
--- a/tests/VkUploadPixelsTests.cpp
+++ b/tests/VkUploadPixelsTests.cpp
@@ -13,9 +13,9 @@
 
 #include "GrContextFactory.h"
 #include "GrContextPriv.h"
-#include "GrProxyProvider.h"
 #include "GrSurfaceProxy.h"
 #include "GrTest.h"
+#include "ProxyUtils.h"
 #include "SkGr.h"
 #include "Test.h"
 #include "vk/GrVkGpu.h"
@@ -52,10 +52,8 @@
     return true;
 }
 
-void basic_texture_test(skiatest::Reporter* reporter, GrContext* context, GrPixelConfig config,
+void basic_texture_test(skiatest::Reporter* reporter, GrContext* context, SkColorType ct,
                         bool renderTarget) {
-    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
-
     const int kWidth = 16;
     const int kHeight = 16;
     SkAutoTMalloc<GrColor> srcBuffer(kWidth*kHeight);
@@ -63,18 +61,8 @@
 
     fill_pixel_data(kWidth, kHeight, srcBuffer.get());
 
-    GrSurfaceDesc surfDesc;
-    surfDesc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
-    surfDesc.fWidth = kWidth;
-    surfDesc.fHeight = kHeight;
-    surfDesc.fConfig = config;
-    surfDesc.fSampleCnt = 1;
-
-    SkColorType ct;
-    SkAssertResult(GrPixelConfigToColorType(config, &ct));
-
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
-            surfDesc, kTopLeft_GrSurfaceOrigin, SkBudgeted::kNo, srcBuffer, 0);
+    auto proxy = sk_gpu_test::MakeTextureProxyFromData(context, renderTarget, kWidth, kHeight, ct,
+                                                       kTopLeft_GrSurfaceOrigin, srcBuffer, 0);
     REPORTER_ASSERT(reporter, proxy);
     if (proxy) {
         sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(proxy);
@@ -103,8 +91,8 @@
                                                                          2));
     }
 
-    proxy = proxyProvider->createTextureProxy(surfDesc, kBottomLeft_GrSurfaceOrigin,
-                                              SkBudgeted::kNo, srcBuffer, 0);
+    proxy = sk_gpu_test::MakeTextureProxyFromData(context, renderTarget, kWidth, kHeight, ct,
+                                                  kBottomLeft_GrSurfaceOrigin, srcBuffer, 0);
     REPORTER_ASSERT(reporter, proxy);
     if (proxy) {
         sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(proxy);
@@ -137,12 +125,12 @@
 
 DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkUploadPixelsTests, reporter, ctxInfo) {
     // RGBA
-    basic_texture_test(reporter, ctxInfo.grContext(), kRGBA_8888_GrPixelConfig, false);
-    basic_texture_test(reporter, ctxInfo.grContext(), kRGBA_8888_GrPixelConfig, true);
+    basic_texture_test(reporter, ctxInfo.grContext(), kRGBA_8888_SkColorType, false);
+    basic_texture_test(reporter, ctxInfo.grContext(), kRGBA_8888_SkColorType, true);
 
     // BGRA
-    basic_texture_test(reporter, ctxInfo.grContext(), kBGRA_8888_GrPixelConfig, false);
-    basic_texture_test(reporter, ctxInfo.grContext(), kBGRA_8888_GrPixelConfig, true);
+    basic_texture_test(reporter, ctxInfo.grContext(), kBGRA_8888_SkColorType, false);
+    basic_texture_test(reporter, ctxInfo.grContext(), kBGRA_8888_SkColorType, true);
 }
 
 #endif
diff --git a/tools/fiddle/fiddle_main.cpp b/tools/fiddle/fiddle_main.cpp
index 891b1ff..578f7cb 100644
--- a/tools/fiddle/fiddle_main.cpp
+++ b/tools/fiddle/fiddle_main.cpp
@@ -164,9 +164,9 @@
             texels[i].fRowBytes = 0;
         }
 
-        backingTexture = resourceProvider->createTexture(
-                backingDesc, SkBudgeted::kNo, kTopLeft_GrSurfaceOrigin, texels.get(), mipLevelCount,
-                SkDestinationSurfaceColorMode::kLegacy);
+        backingTexture = resourceProvider->createTexture(backingDesc, SkBudgeted::kNo, texels.get(),
+                                                         mipLevelCount,
+                                                         SkDestinationSurfaceColorMode::kLegacy);
         if (!backingTexture) {
             return false;
         }
@@ -193,8 +193,7 @@
         GrMipLevel level0 = { data.get(), backingDesc.fWidth*sizeof(uint32_t) };
 
         sk_sp<GrTexture> tmp = resourceProvider->createTexture(
-                backingDesc, SkBudgeted::kNo, kTopLeft_GrSurfaceOrigin, &level0, 1,
-                SkDestinationSurfaceColorMode::kLegacy);
+                backingDesc, SkBudgeted::kNo, &level0, 1, SkDestinationSurfaceColorMode::kLegacy);
         if (!tmp || !tmp->asRenderTarget()) {
             return false;
         }
@@ -222,7 +221,7 @@
         }
 
         backingTextureRenderTarget = resourceProvider->createTexture(
-                backingDesc, SkBudgeted::kNo, kTopLeft_GrSurfaceOrigin, texels.get(), mipLevelCount,
+                backingDesc, SkBudgeted::kNo, texels.get(), mipLevelCount,
                 SkDestinationSurfaceColorMode::kLegacy);
         if (!backingTextureRenderTarget || !backingTextureRenderTarget->asRenderTarget()) {
             return false;
diff --git a/tools/gpu/ProxyUtils.cpp b/tools/gpu/ProxyUtils.cpp
new file mode 100644
index 0000000..e02bf5f
--- /dev/null
+++ b/tools/gpu/ProxyUtils.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "ProxyUtils.h"
+#include "GrContextPriv.h"
+#include "GrDrawingManager.h"
+#include "GrProxyProvider.h"
+
+namespace sk_gpu_test {
+
+sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext* context, bool isRT, int width, int height,
+                                               GrColorType ct, GrSRGBEncoded srgbEncoded,
+                                               GrSurfaceOrigin origin, const void* data,
+                                               size_t rowBytes) {
+    GrSurfaceDesc desc;
+    desc.fConfig = GrColorTypeToPixelConfig(ct, srgbEncoded);
+    desc.fWidth = width;
+    desc.fHeight = height;
+    desc.fFlags = isRT ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
+    auto proxy = context->contextPriv().proxyProvider()->createProxy(
+            desc, origin, SkBackingFit::kExact, SkBudgeted::kYes);
+    if (!proxy) {
+        return nullptr;
+    }
+    auto sContext = context->contextPriv().makeWrappedSurfaceContext(proxy, nullptr);
+    if (!sContext) {
+        return nullptr;
+    }
+    if (!context->contextPriv().writeSurfacePixels(sContext.get(), 0, 0, width, height, ct, nullptr,
+                                                   data, rowBytes)) {
+        return nullptr;
+    }
+    return proxy;
+}
+
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/ProxyUtils.h b/tools/gpu/ProxyUtils.h
new file mode 100644
index 0000000..6dfcd71
--- /dev/null
+++ b/tools/gpu/ProxyUtils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef ProxyUtils_DEFINED
+#define ProxyUtils_DEFINED
+
+#include "GrTextureProxy.h"
+#include "GrTypesPriv.h"
+
+namespace sk_gpu_test {
+
+/** Makes a texture proxy containing the passed in color data. */
+sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext* context, bool isRT, int width, int height,
+                                               GrColorType, GrSRGBEncoded, GrSurfaceOrigin,
+                                               const void* data, size_t rowBytes);
+
+/** Version that assumes GrSRGBEncoded::kNo. */
+inline sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext* context, bool isRT, int width,
+                                                      int height, GrColorType ct,
+                                                      GrSurfaceOrigin origin, const void* data,
+                                                      size_t rowBytes) {
+    return MakeTextureProxyFromData(context, isRT, width, height, ct, GrSRGBEncoded::kNo, origin,
+                                    data, rowBytes);
+}
+
+/** Version that takes SkColorType rather than GrColorType and assumes GrSRGBEncoded::kNo. */
+inline sk_sp<GrTextureProxy> MakeTextureProxyFromData(GrContext* context, bool isRT, int width,
+                                                      int height, SkColorType ct,
+                                                      GrSurfaceOrigin origin, const void* data,
+                                                      size_t rowBytes) {
+    return MakeTextureProxyFromData(context, isRT, width, height, SkColorTypeToGrColorType(ct),
+                                    origin, data, rowBytes);
+}
+
+}  // namespace sk_gpu_test
+
+#endif