More YUV cleanup

* Remove more uses of colortype
* Add back SkImage_GpuYUVA::MakeFromYUVATextures

Bug: skia:7903
Change-Id: I3ee119d190db39c128516dbb78db34fe29ba3cce
Reviewed-on: https://skia-review.googlesource.com/c/165943
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h
index 3047148..98eaa41 100644
--- a/src/gpu/GrCaps.h
+++ b/src/gpu/GrCaps.h
@@ -290,6 +290,14 @@
     /**
      * Special method only for YUVA images. Returns true if the format can be used for a
      * YUVA plane, and the passed in GrPixelConfig will be set to a config that matches
+     * the backend texture.
+     */
+    virtual bool getYUVAConfigFromBackendTexture(const GrBackendTexture& tex,
+                                                 GrPixelConfig*) const = 0;
+
+    /**
+     * Special method only for YUVA images. Returns true if the format can be used for a
+     * YUVA plane, and the passed in GrPixelConfig will be set to a config that matches
      * the backend format.
      */
     virtual bool getYUVAConfigFromBackendFormat(const GrBackendFormat& format,
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 962e496..0829945 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -2941,14 +2941,10 @@
     return validate_sized_format(*glFormat, ct, config, fStandard);
 }
 
-bool GrGLCaps::getYUVAConfigFromBackendFormat(const GrBackendFormat& format,
-                                              GrPixelConfig* config) const {
-    const GrGLenum* glFormat = format.getGLFormat();
-    if (!glFormat) {
-        return false;
-    }
+static bool get_yuva_config(GrGLenum format, GrPixelConfig* config) {
+    *config = kUnknown_GrPixelConfig;
 
-    switch (*glFormat) {
+    switch (format) {
     case GR_GL_ALPHA8:
         *config = kAlpha_8_as_Alpha_GrPixelConfig;
         break;
@@ -2971,6 +2967,24 @@
     return true;
 }
 
+bool GrGLCaps::getYUVAConfigFromBackendTexture(const GrBackendTexture& tex,
+                                               GrPixelConfig* config) const {
+    GrGLTextureInfo texInfo;
+    if (!tex.getGLTextureInfo(&texInfo)) {
+        return false;
+    }
+    return get_yuva_config(texInfo.fFormat, config);
+}
+
+bool GrGLCaps::getYUVAConfigFromBackendFormat(const GrBackendFormat& format,
+                                              GrPixelConfig* config) const {
+    const GrGLenum* glFormat = format.getGLFormat();
+    if (!glFormat) {
+        return false;
+    }
+    return get_yuva_config(*glFormat, config);
+}
+
 
 #ifdef GR_TEST_UTILS
 GrBackendFormat GrGLCaps::onCreateFormatFromBackendTexture(
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index f8b8134..fda673e 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -436,6 +436,8 @@
 
     bool getConfigFromBackendFormat(const GrBackendFormat&, SkColorType,
                                     GrPixelConfig*) const override;
+    bool getYUVAConfigFromBackendTexture(const GrBackendTexture&,
+                                         GrPixelConfig*) const override;
     bool getYUVAConfigFromBackendFormat(const GrBackendFormat&,
                                         GrPixelConfig*) const override;
 
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index 2e6e8d9..c5459b2 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -104,6 +104,17 @@
         return true;
     }
 
+    bool getYUVAConfigFromBackendTexture(const GrBackendTexture& tex,
+                                         GrPixelConfig* config) const override {
+        GrMockTextureInfo texInfo;
+        if (!tex.getMockTextureInfo(&texInfo)) {
+            return false;
+        }
+
+        *config = texInfo.fConfig;
+        return true;
+    }
+
     bool getYUVAConfigFromBackendFormat(const GrBackendFormat& format,
                                         GrPixelConfig* config) const override {
         const GrPixelConfig* mockFormat = format.getMockFormat();
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index 6de830d..6eb775c 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -80,6 +80,11 @@
         return false;
     }
 
+    bool getYUVAConfigFromBackendTexture(const GrBackendTexture&,
+                                         GrPixelConfig*) const override {
+        return false;
+    }
+
     bool getYUVAConfigFromBackendFormat(const GrBackendFormat&,
                                         GrPixelConfig*) const override {
         return false;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 54693d9..01cad06 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -782,14 +782,10 @@
     return validate_image_info(*vkFormat, ct, config);
 }
 
-bool GrVkCaps::getYUVAConfigFromBackendFormat(const GrBackendFormat& format,
-                                              GrPixelConfig* config) const {
-    const VkFormat* vkFormat = format.getVkFormat();
-    if (!vkFormat) {
-        return false;
-    }
+static bool get_yuva_config(VkFormat vkFormat, GrPixelConfig* config) {
+    *config = kUnknown_GrPixelConfig;
 
-    switch (*vkFormat) {
+    switch (vkFormat) {
     case VK_FORMAT_R8_UNORM:
         *config = kAlpha_8_as_Red_GrPixelConfig;
         break;
@@ -809,6 +805,24 @@
     return true;
 }
 
+bool GrVkCaps::getYUVAConfigFromBackendTexture(const GrBackendTexture& tex,
+                                               GrPixelConfig* config) const {
+    GrVkImageInfo imageInfo;
+    if (!tex.getVkImageInfo(&imageInfo)) {
+        return false;
+    }
+    return get_yuva_config(imageInfo.fFormat, config);
+}
+
+bool GrVkCaps::getYUVAConfigFromBackendFormat(const GrBackendFormat& format,
+                                              GrPixelConfig* config) const {
+    const VkFormat* vkFormat = format.getVkFormat();
+    if (!vkFormat) {
+        return false;
+    }
+    return get_yuva_config(*vkFormat, config);
+}
+
 #ifdef GR_TEST_UTILS
 GrBackendFormat GrVkCaps::onCreateFormatFromBackendTexture(
         const GrBackendTexture& backendTex) const {
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 19cdc1d..0154c0b 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -160,6 +160,8 @@
 
     bool getConfigFromBackendFormat(const GrBackendFormat&, SkColorType,
                                     GrPixelConfig*) const override;
+    bool getYUVAConfigFromBackendTexture(const GrBackendTexture&,
+                                         GrPixelConfig*) const override;
     bool getYUVAConfigFromBackendFormat(const GrBackendFormat&,
                                         GrPixelConfig*) const override;
 
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 4ef8b1c..8cf4edb 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -127,8 +127,6 @@
     // of validate_backend_texture.
     GrBackendTexture yuvaTexturesCopy[4];
 
-    bool nv12 = (yuvaIndices[1].fIndex == yuvaIndices[2].fIndex);
-
     for (int i = 0; i < 4; ++i) {
         // Validate that the yuvaIndices refer to valid backend textures.
         const SkYUVAIndex& yuvaIndex = yuvaIndices[i];
@@ -142,31 +140,13 @@
             return nullptr;
         }
 
-        SkColorType ct = kUnknown_SkColorType;
-        if (SkYUVAIndex::kA_Index == i) {
-            // The A plane is always kAlpha8 (for now)
-            ct = kAlpha_8_SkColorType;
-        } else {
-            // The UV planes can either be interleaved or planar. If interleaved the Y plane
-            // should have A8 color type but may be RGBA. We fall back in the latter case below.
-            ct = nv12 && SkYUVAIndex::kY_Index != i ? kRGBA_8888_SkColorType : kAlpha_8_SkColorType;
-        }
-
         if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
             yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
 
-            // TODO: Instead of using assumption about whether it is NV12 format to guess colorType,
-            // actually use channel information here.
-            // Alternate TODO: Don't bother validating.
-            if (!ValidateBackendTexture(ctx, yuvaTexturesCopy[yuvaIndex.fIndex],
-                                        &yuvaTexturesCopy[yuvaIndex.fIndex].fConfig,
-                                        ct, kPremul_SkAlphaType, nullptr)) {
-                // Try RGBA in case the assumed colortype is wrong
-                if (!ValidateBackendTexture(ctx, yuvaTexturesCopy[yuvaIndex.fIndex],
-                                            &yuvaTexturesCopy[yuvaIndex.fIndex].fConfig,
-                                            kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr)) {
-                    return nullptr;
-                }
+            if (!ctx->contextPriv().caps()->getYUVAConfigFromBackendTexture(
+                                                yuvaTexturesCopy[yuvaIndex.fIndex],
+                                                &yuvaTexturesCopy[yuvaIndex.fIndex].fConfig)) {
+                return nullptr;
             }
         }
 
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index ae15f4b..9a54d23 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -96,6 +96,72 @@
     return fRGBProxy;
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx,
+                                             SkYUVColorSpace colorSpace,
+                                             const GrBackendTexture yuvaTextures[],
+                                             const SkYUVAIndex yuvaIndices[4],
+                                             SkISize imageSize,
+                                             GrSurfaceOrigin imageOrigin,
+                                             sk_sp<SkColorSpace> imageColorSpace) {
+    GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
+
+    // We need to make a copy of the input backend textures because we need to preserve the result
+    // of validate_backend_texture.
+    GrBackendTexture yuvaTexturesCopy[4];
+    for (int i = 0; i < 4; ++i) {
+        // Validate that the yuvaIndices refer to valid backend textures.
+        const SkYUVAIndex& yuvaIndex = yuvaIndices[i];
+        if (SkYUVAIndex::kA_Index == i && yuvaIndex.fIndex == -1) {
+            // Meaning the A plane isn't passed in.
+            continue;
+        }
+        if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
+            // Y plane, U plane, and V plane must refer to image sources being passed in. There are
+            // at most 4 image sources being passed in, could not have a index more than 3.
+            return nullptr;
+        }
+
+        if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
+            yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
+
+            if (!ctx->contextPriv().caps()->getYUVAConfigFromBackendTexture(
+                                                yuvaTexturesCopy[yuvaIndex.fIndex],
+                                                &yuvaTexturesCopy[yuvaIndex.fIndex].fConfig)) {
+                return nullptr;
+            }
+        }
+
+        // TODO: Check that for each plane, the channel actually exist in the image source we are
+        // reading from.
+    }
+
+    sk_sp<GrTextureProxy> tempTextureProxies[4]; // build from yuvaTextures
+    for (int i = 0; i < 4; ++i) {
+        // Fill in tempTextureProxies to avoid duplicate texture proxies.
+        int textureIndex = yuvaIndices[i].fIndex;
+
+        // Safely ignore since this means we are missing the A plane.
+        if (textureIndex == -1) {
+            SkASSERT(SkYUVAIndex::kA_Index == i);
+            continue;
+        }
+
+        if (!tempTextureProxies[textureIndex]) {
+            SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
+            tempTextureProxies[textureIndex] =
+                proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], imageOrigin);
+            if (!tempTextureProxies[textureIndex]) {
+                return nullptr;
+            }
+        }
+    }
+
+    return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(),
+                                       kNeedNewImageUniqueID, colorSpace, tempTextureProxies,
+                                       yuvaIndices, imageOrigin, imageColorSpace, SkBudgeted::kYes);
+}
 /////////////////////////////////////////////////////////////////////////////////////////////////
 sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
                                                        SkYUVColorSpace yuvColorSpace,