Verify YUVA channel information and add premultiplied alpha

Bug: skia:7903
Change-Id: Ia5394192febd1ffb6f2dcf700fc551407ceb80c1
Reviewed-on: https://skia-review.googlesource.com/c/170265
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/GrImageTextureMaker.cpp b/src/gpu/GrImageTextureMaker.cpp
index d324c5a..567e91e 100644
--- a/src/gpu/GrImageTextureMaker.cpp
+++ b/src/gpu/GrImageTextureMaker.cpp
@@ -90,6 +90,9 @@
     const GrSamplerState::Filter* filterOrNullForBicubic) {
 
     // Check simple cases to see if we need to fall back to flattening the image
+    // TODO: See if we can relax this -- for example, if filterConstraint
+    //       is kYes_FilterConstraint we still may not need a TextureDomain
+    //       in some cases.
     if (!textureMatrix.isIdentity() || kNo_FilterConstraint != filterConstraint ||
         !coordsLimitedToConstraintRect || !filterOrNullForBicubic) {
         return this->INHERITED::createFragmentProcessor(textureMatrix, constraintRect,
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 1ab100a..61d2456 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -127,6 +127,8 @@
             fragBuilder->codeAppendf(
                 "float a = tmp%d.%c;", _outer.yuvaIndex(3).fIndex,
                                        kChannelToChar[(int)_outer.yuvaIndex(3).fChannel]);
+            // premultiply alpha
+            fragBuilder->codeAppend("yuvOne *= a;");
         } else {
             fragBuilder->codeAppendf("float a = 1.0;");
         }
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index cb0219f..b8aa1a5 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -39,7 +39,6 @@
 #include "SkImage_Gpu.h"
 #include "SkMipMap.h"
 #include "SkTraceEvent.h"
-#include "SkYUVAIndex.h"
 #include "effects/GrYUVtoRGBEffect.h"
 #include "gl/GrGLTexture.h"
 
@@ -127,8 +126,8 @@
     }
 
     sk_sp<GrTextureProxy> tempTextureProxies[4];
-    if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, origin,
-                                                 tempTextureProxies)) {
+    if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
+                                                 origin, tempTextureProxies)) {
         return nullptr;
     }
 
@@ -138,8 +137,9 @@
         return nullptr;
     }
 
+    SkAlphaType at = GetAlphaTypeFromYUVAIndices(yuvaIndices);
     // MDB: this call is okay bc we know 'renderTargetContext' was exact
-    return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, kOpaque_SkAlphaType,
+    return sk_make_sp<SkImage_Gpu>(sk_ref_sp(ctx), kNeedNewImageUniqueID, at,
                                    renderTargetContext->asTextureProxyRef(),
                                    renderTargetContext->colorSpaceInfo().refColorSpace(),
                                    isBudgeted);
@@ -180,8 +180,9 @@
         sk_sp<SkColorSpace> imageColorSpace) {
     GrBackendTexture backendTextureCopy = backendTexture;
 
+    SkAlphaType at = SkImage_GpuBase::GetAlphaTypeFromYUVAIndices(yuvaIndices);
     if (!SkImage_Gpu::ValidateBackendTexture(ctx, backendTextureCopy, &backendTextureCopy.fConfig,
-                                             kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr)) {
+                                             kRGBA_8888_SkColorType, at, nullptr)) {
         return nullptr;
     }
 
diff --git a/src/image/SkImage_GpuBase.cpp b/src/image/SkImage_GpuBase.cpp
index 332e725..8360361 100644
--- a/src/image/SkImage_GpuBase.cpp
+++ b/src/image/SkImage_GpuBase.cpp
@@ -291,7 +291,8 @@
 }
 
 bool SkImage_GpuBase::MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[],
-                                             int numTextures, GrSurfaceOrigin imageOrigin,
+                                             int numTextures, const SkYUVAIndex yuvaIndices[4],
+                                             GrSurfaceOrigin imageOrigin,
                                              sk_sp<GrTextureProxy> tempTextureProxies[4]) {
     GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();
 
@@ -312,6 +313,33 @@
         if (!tempTextureProxies[textureIndex]) {
             return false;
         }
+
+        // Check that each texture contains the channel data for the corresponding YUVA index
+        GrPixelConfig config = yuvaTexturesCopy[textureIndex].fConfig;
+        for (int yuvaIndex = 0; yuvaIndex < SkYUVAIndex::kIndexCount; ++yuvaIndex) {
+            if (yuvaIndices[yuvaIndex].fIndex == textureIndex) {
+                switch (yuvaIndices[yuvaIndex].fChannel) {
+                    case SkColorChannel::kR:
+                        if (kAlpha_8_as_Alpha_GrPixelConfig == config) {
+                            return false;
+                        }
+                        break;
+                    case SkColorChannel::kG:
+                    case SkColorChannel::kB:
+                        if (kAlpha_8_as_Alpha_GrPixelConfig == config ||
+                            kAlpha_8_as_Red_GrPixelConfig == config) {
+                            return false;
+                        }
+                        break;
+                    case SkColorChannel::kA:
+                    default:
+                        if (kRGB_888_GrPixelConfig == config) {
+                            return false;
+                        }
+                        break;
+                }
+            }
+        }
     }
 
     return true;
@@ -329,8 +357,6 @@
     GrPaint paint;
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
-    // TODO: modify the YUVtoRGBEffect to do premul if needed
-    // (e.g., if SkImage_GpuYUVA::fImageAlphaType is kPremul_AlphaType)
     paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(proxies, yuvaIndices,
                                                            yuvColorSpace,
                                                            GrSamplerState::Filter::kNearest));
diff --git a/src/image/SkImage_GpuBase.h b/src/image/SkImage_GpuBase.h
index 38b6065..9a85e56 100644
--- a/src/image/SkImage_GpuBase.h
+++ b/src/image/SkImage_GpuBase.h
@@ -11,6 +11,7 @@
 #include "GrBackendSurface.h"
 #include "GrTypesPriv.h"
 #include "SkImage_Base.h"
+#include "SkYUVAIndex.h"
 
 class GrContext;
 class SkColorSpace;
@@ -62,9 +63,15 @@
                                        GrPixelConfig* config, SkColorType ct, SkAlphaType at,
                                        sk_sp<SkColorSpace> cs);
     static bool MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[],
-                                       int numTextures, GrSurfaceOrigin imageOrigin,
+                                       int numTextures, const SkYUVAIndex [4],
+                                       GrSurfaceOrigin imageOrigin,
                                        sk_sp<GrTextureProxy> tempTextureProxies[4]);
 
+    static SkAlphaType GetAlphaTypeFromYUVAIndices(const SkYUVAIndex yuvaIndices[4]) {
+        return -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
+                                                               : kOpaque_SkAlphaType;
+    }
+
     typedef ReleaseContext TextureContext;
     typedef void(*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
     typedef void(*PromiseDoneProc)(TextureContext textureContext);
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index a492448..ab13835 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -32,8 +32,7 @@
                     // If an alpha channel is present we always switch to kPremul. This is because,
                     // although the planar data is always un-premul, the final interleaved RGB image
                     // is/would-be premul.
-                    -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
-                                                                    : kOpaque_SkAlphaType,
+                    GetAlphaTypeFromYUVAIndices(yuvaIndices),
                     budgeted, imageColorSpace)
         , fNumProxies(numProxies)
         , fYUVColorSpace(colorSpace)
@@ -132,14 +131,11 @@
     }
 
     sk_sp<GrTextureProxy> tempTextureProxies[4];
-    if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, imageOrigin,
-                                                 tempTextureProxies)) {
+    if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices,
+                                                 imageOrigin, tempTextureProxies)) {
         return nullptr;
     }
 
-    // TODO: Check that for each plane, the channel actually exist in the image source we are
-    // reading from.
-
     return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), imageSize.width(), imageSize.height(),
                                        kNeedNewImageUniqueID, colorSpace, tempTextureProxies,
                                        numTextures, yuvaIndices, imageOrigin, imageColorSpace,
diff --git a/src/image/SkImage_GpuYUVA.h b/src/image/SkImage_GpuYUVA.h
index aee49d4..e5a4469 100644
--- a/src/image/SkImage_GpuYUVA.h
+++ b/src/image/SkImage_GpuYUVA.h
@@ -12,7 +12,6 @@
 #include "GrContext.h"
 #include "SkCachedData.h"
 #include "SkImage_GpuBase.h"
-#include "SkYUVAIndex.h"
 
 class GrTexture;
 struct SkYUVASizeInfo;