[graphite] Suppress alpha-only image shader logic via runtime effects

This makes results consistent with Ganesh and CPU, where
alpha-only images produce {0,0,0,a} when sampled in raw
mode, or from runtime effects.

Change-Id: I48d1912c4a745cffd8081b3299eff129f56cb3bf
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/759516
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/graphite/KeyContext.h b/src/gpu/graphite/KeyContext.h
index 478b70b..8d58ce9 100644
--- a/src/gpu/graphite/KeyContext.h
+++ b/src/gpu/graphite/KeyContext.h
@@ -71,6 +71,13 @@
 
     const SkPMColor4f& paintColor() const { return fPaintColor; }
 
+    enum class Scope {
+        kDefault,
+        kRuntimeEffect,
+    };
+
+    Scope scope() const { return fScope; }
+
 protected:
     Recorder* fRecorder = nullptr;
     SkM44 fLocal2Dev;
@@ -79,6 +86,7 @@
     RuntimeEffectDictionary* fRTEffectDict;
     SkColorInfo fDstColorInfo;
     SkPMColor4f fPaintColor = SK_PMColor4fBLACK;
+    Scope fScope = Scope::kDefault;
 
 private:
     const Caps* fCaps = nullptr;
@@ -119,6 +127,17 @@
     KeyContextWithColorInfo& operator=(const KeyContextWithColorInfo&) = delete;
 };
 
+class KeyContextWithScope : public KeyContext {
+public:
+    KeyContextWithScope(const KeyContext& other, KeyContext::Scope scope) : KeyContext(other) {
+        fScope = scope;
+    }
+
+private:
+    KeyContextWithScope(const KeyContextWithScope&) = delete;
+    KeyContextWithScope& operator=(const KeyContextWithScope&) = delete;
+};
+
 } // namespace skgpu::graphite
 
 #endif // skgpu_graphite_KeyContext_DEFINED
diff --git a/src/gpu/graphite/KeyHelpers.cpp b/src/gpu/graphite/KeyHelpers.cpp
index 9436b58..a0c9553 100644
--- a/src/gpu/graphite/KeyHelpers.cpp
+++ b/src/gpu/graphite/KeyHelpers.cpp
@@ -1009,34 +1009,37 @@
 
     using ChildType = SkRuntimeEffect::ChildType;
 
+    KeyContextWithScope childContext(keyContext, KeyContext::Scope::kRuntimeEffect);
+
     for (size_t index = 0; index < children.size(); ++index) {
         const SkRuntimeEffect::ChildPtr& child = children[index];
         std::optional<ChildType> type = child.type();
         if (type == ChildType::kShader) {
-            AddToKey(keyContext, builder, gatherer, child.shader());
+            AddToKey(childContext, builder, gatherer, child.shader());
         } else if (type == ChildType::kColorFilter) {
-            AddToKey(keyContext, builder, gatherer, child.colorFilter());
+            AddToKey(childContext, builder, gatherer, child.colorFilter());
         } else if (type == ChildType::kBlender) {
-            AddToKey(keyContext, builder, gatherer, child.blender());
+            AddToKey(childContext, builder, gatherer, child.blender());
         } else {
             // We don't have a child effect. Substitute in a no-op effect.
             switch (childInfo[index].type) {
                 case ChildType::kShader:
                     // A missing shader returns transparent black
-                    SolidColorShaderBlock::BeginBlock(keyContext, builder, gatherer, {0, 0, 0, 0});
+                    SolidColorShaderBlock::BeginBlock(
+                            childContext, builder, gatherer, {0, 0, 0, 0});
                     builder->endBlock();
                     break;
 
                 case ChildType::kColorFilter:
                     // A "passthrough" color filter returns the input color as-is.
-                    PriorOutputBlock::BeginBlock(keyContext, builder, gatherer);
+                    PriorOutputBlock::BeginBlock(childContext, builder, gatherer);
                     builder->endBlock();
                     break;
 
                 case ChildType::kBlender:
                     // A "passthrough" blender performs `blend_src_over(src, dest)`.
                     BlendModeBlenderBlock::BeginBlock(
-                            keyContext, builder, gatherer, SkBlendMode::kSrcOver);
+                            childContext, builder, gatherer, SkBlendMode::kSrcOver);
                     builder->endBlock();
                     break;
             }
@@ -1481,7 +1484,7 @@
     skgpu::Swizzle readSwizzle = view.swizzle();
     // If the color type is alpha-only, propagate the alpha value to the other channels.
     if (imageToDraw->isAlphaOnly()) {
-        readSwizzle = skgpu::Swizzle::Concat(readSwizzle, skgpu::Swizzle("aaaa"));
+        readSwizzle = skgpu::Swizzle::Concat(readSwizzle, skgpu::Swizzle("000a"));
     }
     imgData.fReadSwizzle = swizzle_class_to_read_enum(readSwizzle);
 
@@ -1500,7 +1503,7 @@
                                                 keyContext.dstColorInfo().colorSpace(),
                                                 keyContext.dstColorInfo().alphaType());
 
-        if (imageToDraw->isAlphaOnly()) {
+        if (imageToDraw->isAlphaOnly() && keyContext.scope() != KeyContext::Scope::kRuntimeEffect) {
             Blend(keyContext, builder, gatherer,
                   /* addBlendToKey= */ [&] () -> void {
                       AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kDstIn);