Pass color types when creating texture with initial data.

One describes the color type use case for the texture and the other
the color type of the texel data, a la writePixels().

Bug: skia:6718

Change-Id: I3ca2ab9f76aaeca4b2861a171b1aaacaa0709d1e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240679
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index a7a3bb1..efc000f 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -99,11 +99,12 @@
     return false;
 }
 
-static bool validate_texel_levels(int w, int h, const GrMipLevel* texels, int mipLevelCount,
-                                  int bpp, const GrCaps* caps) {
+static bool validate_texel_levels(int w, int h, GrColorType texelColorType,
+                                  const GrMipLevel* texels, int mipLevelCount, const GrCaps* caps) {
     SkASSERT(mipLevelCount > 0);
     bool hasBasePixels = texels[0].fPixels;
     int levelsWithPixelsCnt = 0;
+    auto bpp = GrColorTypeBytesPerPixel(texelColorType);
     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
         if (texels[currentMipLevel].fPixels) {
             const size_t minRowBytes = w * bpp;
@@ -141,21 +142,20 @@
     return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
 }
 
-sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
-                                      const GrBackendFormat& format,
-                                      GrRenderable renderable,
-                                      int renderTargetSampleCnt,
-                                      SkBudgeted budgeted,
-                                      GrProtected isProtected,
-                                      const GrMipLevel texels[],
-                                      int texelLevelCount) {
-    TRACE_EVENT0("skia.gpu", TRACE_FUNC);
+sk_sp<GrTexture> GrGpu::createTextureCommon(const GrSurfaceDesc& desc,
+                                            const GrBackendFormat& format,
+                                            GrRenderable renderable,
+                                            int renderTargetSampleCnt,
+                                            SkBudgeted budgeted,
+                                            GrProtected isProtected,
+                                            int mipLevelCount,
+                                            uint32_t levelClearMask) {
     if (this->caps()->isFormatCompressed(format)) {
         // Call GrGpu::createCompressedTexture.
         return nullptr;
     }
 
-    GrMipMapped mipMapped = texelLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
+    GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
     if (!this->caps()->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
                                              renderable, renderTargetSampleCnt, mipMapped)) {
         return nullptr;
@@ -167,9 +167,64 @@
     }
     // Attempt to catch un- or wrongly initialized sample counts.
     SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
+    this->handleDirtyContext();
+    auto tex = this->onCreateTexture(desc,
+                                     format,
+                                     renderable,
+                                     renderTargetSampleCnt,
+                                     budgeted,
+                                     isProtected,
+                                     mipLevelCount,
+                                     levelClearMask);
+    if (tex) {
+        SkASSERT(tex->backendFormat() == format);
+        SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
+        if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
+            tex->resourcePriv().removeScratchKey();
+        }
+        fStats.incTextureCreates();
+        if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
+            SkASSERT(GrRenderable::kYes == renderable);
+            tex->asRenderTarget()->setRequiresManualMSAAResolve();
+        }
+    }
+    return tex;
+}
+
+sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
+                                      const GrBackendFormat& format,
+                                      GrRenderable renderable,
+                                      int renderTargetSampleCnt,
+                                      GrMipMapped mipMapped,
+                                      SkBudgeted budgeted,
+                                      GrProtected isProtected) {
+    int mipLevelCount = 1;
+    if (mipMapped == GrMipMapped::kYes) {
+        mipLevelCount = 32 - SkCLZ(static_cast<uint32_t>(SkTMax(desc.fWidth, desc.fHeight)));
+    }
+    uint32_t levelClearMask =
+            this->caps()->shouldInitializeTextures() ? (1 << mipLevelCount) - 1 : 0;
+    auto tex = this->createTextureCommon(desc, format, renderable, renderTargetSampleCnt, budgeted,
+                                         isProtected, mipLevelCount, levelClearMask);
+    if (tex && mipMapped == GrMipMapped::kYes && levelClearMask) {
+        tex->texturePriv().markMipMapsClean();
+    }
+    return tex;
+}
+
+sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
+                                      const GrBackendFormat& format,
+                                      GrRenderable renderable,
+                                      int renderTargetSampleCnt,
+                                      SkBudgeted budgeted,
+                                      GrProtected isProtected,
+                                      GrColorType textureColorType,
+                                      GrColorType srcColorType,
+                                      const GrMipLevel texels[],
+                                      int texelLevelCount) {
+    TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     if (texelLevelCount) {
-        int bpp = GrBytesPerPixel(desc.fConfig);
-        if (!validate_texel_levels(desc.fWidth, desc.fHeight, texels, texelLevelCount, bpp,
+        if (!validate_texel_levels(desc.fWidth, desc.fHeight, srcColorType, texels, texelLevelCount,
                                    this->caps())) {
             return nullptr;
         }
@@ -189,31 +244,15 @@
         }
     }
 
-    this->handleDirtyContext();
-    sk_sp<GrTexture> tex = this->onCreateTexture(desc,
-                                                 format,
-                                                 renderable,
-                                                 renderTargetSampleCnt,
-                                                 budgeted,
-                                                 isProtected,
-                                                 mipLevelCount,
-                                                 levelClearMask);
-
+    auto tex = this->createTextureCommon(desc, format, renderable, renderTargetSampleCnt, budgeted,
+                                         isProtected, texelLevelCount, levelClearMask);
     if (tex) {
-        SkASSERT(tex->backendFormat() == format);
-        SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
-        if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
-            tex->resourcePriv().removeScratchKey();
-        }
-        fStats.incTextureCreates();
         bool markMipLevelsClean = false;
         // Currently if level 0 does not have pixels then no other level may, as enforced by
         // validate_texel_levels.
         if (texelLevelCount && texels[0].fPixels) {
-            auto textureColorType = GrPixelConfigToColorType(desc.fConfig);
-            auto dataColorType = textureColorType;
             if (!this->writePixels(tex.get(), 0, 0, desc.fWidth, desc.fHeight, textureColorType,
-                                   dataColorType, texels, texelLevelCount)) {
+                                   srcColorType, texels, texelLevelCount)) {
                 return nullptr;
             }
             // Currently if level[1] of mip map has pixel data then so must all other levels.
@@ -226,21 +265,10 @@
         if (markMipLevelsClean) {
             tex->texturePriv().markMipMapsClean();
         }
-        if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
-            SkASSERT(GrRenderable::kYes == renderable);
-            tex->asRenderTarget()->setRequiresManualMSAAResolve();
-        }
     }
     return tex;
 }
 
-sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
-                                      GrRenderable renderable, int renderTargetSampleCnt,
-                                      SkBudgeted budgeted, GrProtected isProtected) {
-    return this->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
-                               isProtected, nullptr, 0);
-}
-
 sk_sp<GrTexture> GrGpu::createCompressedTexture(int width, int height,
                                                 const GrBackendFormat& format,
                                                 SkImage::CompressionType compressionType,
@@ -454,8 +482,7 @@
         return false;
     }
 
-    size_t bpp = GrColorTypeBytesPerPixel(srcColorType);
-    if (!validate_texel_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
+    if (!validate_texel_levels(width, height, srcColorType, texels, mipLevelCount, this->caps())) {
         return false;
     }
 
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 80677b9..3ef00d5 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -103,22 +103,35 @@
      *                       If mipLevelCount > 1 and texels[i].fPixels != nullptr for any i > 0
      *                       then all levels must have non-null pixels. All levels must have
      *                       non-null pixels if GrCaps::createTextureMustSpecifyAllLevels() is true.
+     * @param textureColorType The color type interpretation of the texture for the purpose of
+     *                       of uploading texel data.
+     * @param srcColorType   The color type of data in texels[].
      * @param texelLevelCount the number of levels in 'texels'. May be 0, 1, or
      *                       floor(max((log2(desc.fWidth), log2(desc.fHeight)))). It must be the
      *                       latter if GrCaps::createTextureMustSpecifyAllLevels() is true.
      * @return  The texture object if successful, otherwise nullptr.
      */
-    sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
-                                   GrRenderable renderable, int renderTargetSampleCnt, SkBudgeted,
-                                   GrProtected isProtected, const GrMipLevel texels[],
+    sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc,
+                                   const GrBackendFormat& format,
+                                   GrRenderable renderable,
+                                   int renderTargetSampleCnt,
+                                   SkBudgeted,
+                                   GrProtected isProtected,
+                                   GrColorType textureColorType,
+                                   GrColorType srcColorType,
+                                   const GrMipLevel texels[],
                                    int texelLevelCount);
 
     /**
      * Simplified createTexture() interface for when there is no initial texel data to upload.
      */
-    sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
-                                   GrRenderable renderable, int renderTargetSampleCnt,
-                                   SkBudgeted budgeted, GrProtected isProtected);
+    sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc,
+                                   const GrBackendFormat& format,
+                                   GrRenderable renderable,
+                                   int renderTargetSampleCnt,
+                                   GrMipMapped,
+                                   SkBudgeted budgeted,
+                                   GrProtected isProtected);
 
     sk_sp<GrTexture> createCompressedTexture(int width, int height, const GrBackendFormat&,
                                              SkImage::CompressionType, SkBudgeted, const void* data,
@@ -615,6 +628,15 @@
     virtual void onDumpJSON(SkJSONWriter*) const {}
 #endif
 
+    sk_sp<GrTexture> createTextureCommon(const GrSurfaceDesc& desc,
+                                         const GrBackendFormat& format,
+                                         GrRenderable renderable,
+                                         int renderTargetSampleCnt,
+                                         SkBudgeted budgeted,
+                                         GrProtected isProtected,
+                                         int mipLevelCnt,
+                                         uint32_t levelClearMask);
+
     void resetContext() {
         this->onResetContext(fResetBits);
         fResetBits = 0;
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index 46ea7b7..e4e0e84 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -150,7 +150,7 @@
                                                     isProtected);
     } else {
         tex = resourceProvider->createTexture(desc, format, renderable, renderTargetSampleCnt,
-                                              budgeted, isProtected);
+                                              GrMipMapped::kNo, budgeted, isProtected);
     }
     if (!tex) {
         return nullptr;
@@ -297,8 +297,8 @@
                 GrMipLevel mipLevel = { pixMap.addr(), pixMap.rowBytes() };
 
                 return LazyCallbackResult(resourceProvider->createTexture(
-                        desc, format, GrRenderable::kNo, sampleCnt, budgeted, fit, GrProtected::kNo,
-                        ct, mipLevel));
+                        desc, format, ct, GrRenderable::kNo, sampleCnt, budgeted, fit,
+                        GrProtected::kNo, mipLevel));
             },
             format, desc, GrRenderable::kNo, sampleCnt, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo,
             GrMipMapsStatus::kNotAllocated, surfaceFlags, fit, budgeted, GrProtected::kNo,
@@ -360,8 +360,8 @@
 
     GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(bitmap.info());
 
-    GrColorType grColorType = SkColorTypeToGrColorType(bitmap.info().colorType());
-    GrBackendFormat format = this->caps()->getDefaultBackendFormat(grColorType, GrRenderable::kNo);
+    GrBackendFormat format = this->caps()->getDefaultBackendFormat(
+            SkColorTypeToGrColorType(bitmap.info().colorType()), GrRenderable::kNo);
     if (!format.isValid()) {
         SkBitmap copy8888;
         if (!copy8888.tryAllocPixels(bitmap.info().makeColorType(kRGBA_8888_SkColorType)) ||
@@ -371,8 +371,7 @@
         copy8888.setImmutable();
         baseLevel = SkMakeImageFromRasterBitmap(copy8888, kNever_SkCopyPixelsMode);
         desc.fConfig = kRGBA_8888_GrPixelConfig;
-        grColorType = GrColorType::kRGBA_8888;
-        format = this->caps()->getDefaultBackendFormat(grColorType, GrRenderable::kNo);
+        format = this->caps()->getDefaultBackendFormat(GrColorType::kRGBA_8888, GrRenderable::kNo);
         if (!format.isValid()) {
             return nullptr;
         }
@@ -393,22 +392,21 @@
                 SkPixmap pixmap;
                 SkAssertResult(baseLevel->peekPixels(&pixmap));
 
-                // DDL TODO: Instead of copying all this info into GrMipLevels we should just plumb
-                // the use of SkMipMap down through Ganesh.
                 texels[0].fPixels = pixmap.addr();
                 texels[0].fRowBytes = pixmap.rowBytes();
 
+                auto colorType = SkColorTypeToGrColorType(pixmap.colorType());
                 for (int i = 1; i < mipLevelCount; ++i) {
                     SkMipMap::Level generatedMipLevel;
                     mipmaps->getLevel(i - 1, &generatedMipLevel);
                     texels[i].fPixels = generatedMipLevel.fPixmap.addr();
                     texels[i].fRowBytes = generatedMipLevel.fPixmap.rowBytes();
                     SkASSERT(texels[i].fPixels);
+                    SkASSERT(generatedMipLevel.fPixmap.colorType() == pixmap.colorType());
                 }
-
                 return LazyCallbackResult(resourceProvider->createTexture(
-                        desc, format, GrRenderable::kNo, 1, SkBudgeted::kYes, GrProtected::kNo,
-                        texels.get(), mipLevelCount));
+                        desc, format, colorType, GrRenderable::kNo, 1, SkBudgeted::kYes,
+                        GrProtected::kNo, texels.get(), mipLevelCount));
             },
             format, desc, GrRenderable::kNo, 1, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes,
             GrMipMapsStatus::kValid, GrInternalSurfaceFlags::kNone, SkBackingFit::kExact,
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 6d6352f..8408873 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -44,33 +44,36 @@
 
 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
 // to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
-static bool prepare_level(const GrMipLevel& inLevel, size_t bpp, int w, int h, bool rowBytesSupport,
+static bool prepare_level(const GrMipLevel& inLevel, int w, int h, bool rowBytesSupport,
+                          GrColorType origColorType, GrColorType allowedColorType,
                           GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
-    size_t minRB = w * bpp;
     if (!inLevel.fPixels) {
         outLevel->fPixels = nullptr;
         outLevel->fRowBytes = 0;
         return true;
     }
+    size_t minRB = w * GrColorTypeBytesPerPixel(origColorType);
     size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
     if (actualRB < minRB) {
         return false;
     }
-    if (actualRB == minRB || rowBytesSupport) {
+    if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
         outLevel->fRowBytes = actualRB;
         outLevel->fPixels = inLevel.fPixels;
-    } else {
-        data->reset(new char[minRB * h]);
-        outLevel->fPixels = data->get();
-        outLevel->fRowBytes = minRB;
-        SkRectMemcpy(data->get(), outLevel->fRowBytes, inLevel.fPixels, inLevel.fRowBytes, minRB,
-                     h);
+        return true;
     }
-    return true;
+    auto tempRB = w * GrColorTypeBytesPerPixel(allowedColorType);
+    data->reset(new char[tempRB * h]);
+    outLevel->fPixels = data->get();
+    outLevel->fRowBytes = minRB;
+    GrPixelInfo srcInfo(origColorType,    kUnpremul_SkAlphaType, nullptr, w, h);
+    GrPixelInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, w, h);
+    return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
 }
 
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
                                                    const GrBackendFormat& format,
+                                                   GrColorType colorType,
                                                    GrRenderable renderable,
                                                    int renderTargetSampleCnt,
                                                    SkBudgeted budgeted,
@@ -90,6 +93,11 @@
                                       renderTargetSampleCnt, mipMapped)) {
         return nullptr;
     }
+    auto allowedColorType =
+            this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
+    if (allowedColorType == GrColorType::kUnknown) {
+        return nullptr;
+    }
     bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
     SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
@@ -98,10 +106,9 @@
         tmpDatas.reset(mipLevelCount);
         int w = desc.fWidth;
         int h = desc.fHeight;
-        size_t bpp = GrBytesPerPixel(desc.fConfig);
         for (int i = 0; i < mipLevelCount; ++i) {
-            if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, &tmpTexels[i],
-                               &tmpDatas[i])) {
+            if (!prepare_level(texels[i], w, h, rowBytesSupport, colorType, allowedColorType,
+                               &tmpTexels[i], &tmpDatas[i])) {
                 return nullptr;
             }
             w = std::max(w / 2, 1);
@@ -109,7 +116,7 @@
         }
     }
     return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
-                               isProtected, tmpTexels.get(), mipLevelCount);
+                               isProtected, colorType, colorType, tmpTexels.get(), mipLevelCount);
 }
 
 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
@@ -129,12 +136,12 @@
 
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
                                                    const GrBackendFormat& format,
+                                                   GrColorType colorType,
                                                    GrRenderable renderable,
                                                    int renderTargetSampleCnt,
                                                    SkBudgeted budgeted,
                                                    SkBackingFit fit,
                                                    GrProtected isProtected,
-                                                   GrColorType srcColorType,
                                                    const GrMipLevel& mipLevel) {
     ASSERT_SINGLE_OWNER
 
@@ -154,43 +161,35 @@
     GrContext* context = fGpu->getContext();
     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
 
-    bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
-
-    size_t bpp = GrBytesPerPixel(desc.fConfig);
-    std::unique_ptr<char[]> tmpData;
-    GrMipLevel tmpLevel;
-    if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, &tmpLevel,
-                       &tmpData)) {
-        return nullptr;
+    sk_sp<GrTexture> tex;
+    if (SkBackingFit::kApprox == fit) {
+        tex = this->createApproxTexture(desc, format, renderable, renderTargetSampleCnt,
+                                        isProtected);
+        if (!tex) {
+            return nullptr;
+        }
+        sk_sp<GrTextureProxy> proxy = proxyProvider->createWrapped(
+                tex, colorType, kTopLeft_GrSurfaceOrigin, GrSurfaceProxy::UseAllocator::kYes);
+        if (!proxy) {
+            return nullptr;
+        }
+        // Here we don't really know the alpha type of the data we want to upload. All we really
+        // care about is that it is not converted. So we use the same alpha type for the data
+        // and the surface context.
+        static constexpr auto kAlphaType = kUnpremul_SkAlphaType;
+        auto sContext =
+                context->priv().makeWrappedSurfaceContext(std::move(proxy), colorType, kAlphaType);
+        if (!sContext) {
+            return nullptr;
+        }
+        GrPixelInfo srcInfo(colorType, kAlphaType, nullptr, desc.fWidth, desc.fHeight);
+        SkAssertResult(
+                sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, {0, 0}));
+        return tex;
+    } else {
+        return this->createTexture(desc, format, colorType, renderable, renderTargetSampleCnt,
+                                   budgeted, isProtected, &mipLevel, 1);
     }
-
-    sk_sp<GrTexture> tex =
-            (SkBackingFit::kApprox == fit)
-                    ? this->createApproxTexture(desc, format, renderable, renderTargetSampleCnt,
-                                                isProtected)
-                    : this->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
-                                          isProtected);
-    if (!tex) {
-        return nullptr;
-    }
-
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createWrapped(
-            tex, srcColorType, kTopLeft_GrSurfaceOrigin, GrSurfaceProxy::UseAllocator::kYes);
-    if (!proxy) {
-        return nullptr;
-    }
-    // Here we don't really know the alpha type of the data we want to upload. All we really
-    // care about is that it is not converted. So we use the same alpha type for the data
-    // and the surface context.
-    static constexpr auto kAlphaType = kUnpremul_SkAlphaType;
-    auto sContext =
-            context->priv().makeWrappedSurfaceContext(std::move(proxy), srcColorType, kAlphaType);
-    if (!sContext) {
-        return nullptr;
-    }
-    GrPixelInfo srcInfo(srcColorType, kAlphaType, nullptr, desc.fWidth, desc.fHeight);
-    SkAssertResult(sContext->writePixels(srcInfo, tmpLevel.fPixels, tmpLevel.fRowBytes, {0, 0}));
-    return tex;
 }
 
 sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(int width, int height,
@@ -209,6 +208,7 @@
                                                    const GrBackendFormat& format,
                                                    GrRenderable renderable,
                                                    int renderTargetSampleCnt,
+                                                   GrMipMapped mipMapped,
                                                    SkBudgeted budgeted,
                                                    GrProtected isProtected) {
     ASSERT_SINGLE_OWNER
@@ -217,12 +217,13 @@
     }
 
     if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
-                                      renderTargetSampleCnt, GrMipMapped::kNo)) {
+                                      renderTargetSampleCnt, mipMapped)) {
         return nullptr;
     }
 
     // Compressed textures are read-only so they don't support re-use for scratch.
-    if (!GrPixelConfigIsCompressed(desc.fConfig)) {
+    // TODO: Support GrMipMapped::kYes in scratch texture lookup here.
+    if (!GrPixelConfigIsCompressed(desc.fConfig) && mipMapped == GrMipMapped::kNo) {
         sk_sp<GrTexture> tex = this->getExactScratch(
                 desc, format, renderable, renderTargetSampleCnt, budgeted, isProtected);
         if (tex) {
@@ -230,7 +231,7 @@
         }
     }
 
-    return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
+    return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, mipMapped, budgeted,
                                isProtected);
 }
 
@@ -292,7 +293,7 @@
     }
 
     return fGpu->createTexture(copyDesc, format, renderable, renderTargetSampleCnt,
-                               SkBudgeted::kYes, isProtected);
+                               GrMipMapped::kNo, SkBudgeted::kYes, isProtected);
 }
 
 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc,
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 7d77bbf..78ebe4e 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -70,11 +70,18 @@
                                    const GrBackendFormat& format,
                                    GrRenderable renderable,
                                    int renderTargetSampleCnt,
+                                   GrMipMapped mipMapped,
                                    SkBudgeted budgeted,
                                    GrProtected isProtected);
 
+    /**
+     * Create an exact fit texture with initial data to upload. The color type must be valid
+     * for the format and also describe the texel data. This will ensure any conversions that
+     * need to get applied to the data before upload are applied.
+     */
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc,
                                    const GrBackendFormat& format,
+                                   GrColorType colorType,
                                    GrRenderable renderable,
                                    int renderTargetSampleCnt,
                                    SkBudgeted budgeted,
@@ -82,15 +89,19 @@
                                    const GrMipLevel texels[],
                                    int mipLevelCount);
 
-    /** Create a potentially loose fit texture with the provided data */
+    /**
+     * Create a potentially loose fit texture with the provided data. The color type must be valid
+     * for the format and also describe the texel data. This will ensure any conversions that
+     * need to get applied to the data before upload are applied.
+     */
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc,
                                    const GrBackendFormat& format,
+                                   GrColorType srcColorType,
                                    GrRenderable renderable,
                                    int renderTargetSampleCnt,
                                    SkBudgeted budgeted,
                                    SkBackingFit fit,
                                    GrProtected isProtected,
-                                   GrColorType srcColorType,
                                    const GrMipLevel& mipLevel);
 
     /**
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index 7f2c963..03c7e61 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -162,6 +162,7 @@
                                                    int minStencilSampleCount,
                                                    GrRenderable renderable,
                                                    GrMipMapped mipMapped) const {
+    SkASSERT(mipMapped == GrMipMapped::kNo || fFit == SkBackingFit::kExact);
     SkASSERT(!this->isLazy());
     SkASSERT(!fTarget);
     GrSurfaceDesc desc;
@@ -170,44 +171,12 @@
     desc.fConfig = fConfig;
 
     sk_sp<GrSurface> surface;
-    if (GrMipMapped::kYes == mipMapped) {
-        SkASSERT(SkBackingFit::kExact == fFit);
-
-        // SkMipMap doesn't include the base level in the level count so we have to add 1
-        int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
-        // We should have caught the case where mipCount == 1 when making the proxy and instead
-        // created a non-mipmapped proxy.
-        SkASSERT(mipCount > 1);
-        std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipCount]);
-
-        // We don't want to upload any texel data
-        for (int i = 0; i < mipCount; i++) {
-            texels[i].fPixels = nullptr;
-            texels[i].fRowBytes = 0;
-        }
-        surface = resourceProvider->createTexture(desc, fFormat, renderable, sampleCnt, fBudgeted,
-                                                  fIsProtected, texels.get(), mipCount);
-#ifdef SK_DEBUG
-        if (surface) {
-            const GrTextureProxy* thisTexProxy = this->asTextureProxy();
-            SkASSERT(thisTexProxy);
-
-            GrTexture* texture = surface->asTexture();
-            SkASSERT(texture);
-
-            SkASSERT(GrMipMapped::kYes == texture->texturePriv().mipMapped());
-            SkASSERT(thisTexProxy->fInitialMipMapsStatus == texture->texturePriv().mipMapsStatus());
-        }
-#endif
+    if (SkBackingFit::kApprox == fFit) {
+        surface = resourceProvider->createApproxTexture(desc, fFormat, renderable, sampleCnt,
+                                                        fIsProtected);
     } else {
-        if (SkBackingFit::kApprox == fFit) {
-            surface = resourceProvider->createApproxTexture(desc, fFormat, renderable, sampleCnt,
-                                                            fIsProtected);
-        } else {
-            surface =
-                    resourceProvider->createTexture(desc, fFormat, renderable, sampleCnt, fBudgeted,
-                                                    fIsProtected);
-        }
+        surface = resourceProvider->createTexture(desc, fFormat, renderable, sampleCnt, mipMapped,
+                                                  fBudgeted, fIsProtected);
     }
     if (!surface) {
         return nullptr;
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp
index 92fca8e..55d8f97 100644
--- a/src/gpu/ccpr/GrCCAtlas.cpp
+++ b/src/gpu/ccpr/GrCCAtlas.cpp
@@ -122,8 +122,8 @@
                     desc.fHeight = fHeight;
                     desc.fConfig = pixelConfig;
                     fBackingTexture = resourceProvider->createTexture(
-                            desc, format, GrRenderable::kYes, sampleCount, SkBudgeted::kYes,
-                            GrProtected::kNo);
+                            desc, format, GrRenderable::kYes, sampleCount, GrMipMapped::kNo,
+                            SkBudgeted::kYes, GrProtected::kNo);
                 }
                 return fBackingTexture;
             },