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/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,