Support structs in runtime effects

Uses the pipeline-stage callback mechanism. It mangles the type name
(with a test to verify that this works), and then calls defineStruct
with the entire SkSL struct definition string.

Bug: skia:10939
Change-Id: If14cf1b11faaa80ad8d4086cdacf68532bac43fc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/368809
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index a36f03f..f364c53 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -401,3 +401,44 @@
     REPORTER_ASSERT(r, c.fB == 0.5625f);
     REPORTER_ASSERT(r, c.fA == 1.0f);
 }
+
+static void test_RuntimeEffectStructNameReuse(skiatest::Reporter* r, GrRecordingContext* rContext) {
+    // Test that two different runtime effects can reuse struct names in a single paint operation
+    auto [childEffect, err] = SkRuntimeEffect::Make(SkString(
+        "uniform shader paint;"
+        "struct S { half4 rgba; };"
+        "void process(inout S s) { s.rgba.rgb *= 0.5; }"
+        "half4 main() { S s; s.rgba = sample(paint); process(s); return s.rgba; }"
+    ));
+    REPORTER_ASSERT(r, childEffect, "%s\n", err.c_str());
+    sk_sp<SkShader> nullChild = nullptr;
+    sk_sp<SkShader> child = childEffect->makeShader(/*uniforms=*/nullptr, &nullChild,
+                                                    /*childCount=*/1, /*localMatrix=*/nullptr,
+                                                    /*isOpaque=*/false);
+
+    SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+    sk_sp<SkSurface> surface = rContext
+                                    ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info)
+                                    : SkSurface::MakeRaster(info);
+    REPORTER_ASSERT(r, surface);
+
+    TestEffect effect(r, surface);
+    effect.build(
+            "uniform shader child;"
+            "struct S { float2 coord; };"
+            "void process(inout S s) { s.coord = s.coord.yx; }"
+            "half4 main(float2 p) { S s; s.coord = p; process(s); return sample(child, s.coord); "
+            "}");
+    effect.child("child") = child;
+    effect.test(0xFF00407F, [](SkCanvas*, SkPaint* paint) {
+        paint->setColor4f({0.99608f, 0.50196f, 0.0f, 1.0f});
+    });
+}
+
+DEF_TEST(SkRuntimeStructNameReuse, r) {
+    test_RuntimeEffectStructNameReuse(r, nullptr);
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeStructNameReuse_GPU, r, ctxInfo) {
+    test_RuntimeEffectStructNameReuse(r, ctxInfo.directContext());
+}
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index 214d52e..dcce46e 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -130,7 +130,7 @@
 SKSL_TEST(SkSLIntFoldingES2,                   "folding/IntFoldingES2.sksl")
 SKSL_TEST(SkSLFloatFolding,                    "folding/FloatFolding.sksl")
 SKSL_TEST(SkSLMatrixFoldingES2,                "folding/MatrixFoldingES2.sksl")
-SKSL_TEST_CPU(SkSLSelfAssignment,              "folding/SelfAssignment.sksl")
+SKSL_TEST(SkSLSelfAssignment,                  "folding/SelfAssignment.sksl")
 SKSL_TEST(SkSLShortCircuitBoolFolding,         "folding/ShortCircuitBoolFolding.sksl")
 SKSL_TEST(SkSLVectorScalarFolding,             "folding/VectorScalarFolding.sksl")
 SKSL_TEST(SkSLVectorVectorFolding,             "folding/VectorVectorFolding.sksl")
@@ -173,6 +173,7 @@
 SKSL_TEST(SkSLScalarConversionConstructorsES2, "shared/ScalarConversionConstructorsES2.sksl")
 SKSL_TEST(SkSLStackingVectorCasts,             "shared/StackingVectorCasts.sksl")
 SKSL_TEST(SkSLStaticIf,                        "shared/StaticIf.sksl")
+SKSL_TEST(SkSLStructsInFunctions,              "shared/StructsInFunctions.sksl")
 SKSL_TEST(SkSLSwizzleBoolConstants,            "shared/SwizzleBoolConstants.sksl")
 SKSL_TEST(SkSLSwizzleByConstantIndex,          "shared/SwizzleByConstantIndex.sksl")
 SKSL_TEST(SkSLSwizzleConstants,                "shared/SwizzleConstants.sksl")
@@ -192,12 +193,6 @@
 */
 
 /*
-TODO(skia:10939): enable this test when Runtime Effects supports structs in function signatures
-SKSL_TEST(SkSLSelfAssignment,                  "folding/SelfAssignment.sksl")
-SKSL_TEST(SkSLStructsInFunctions,              "shared/StructsInFunctions.sksl")
-*/
-
-/*
 TODO(skia:11209): enable these tests when Runtime Effects have support for ES3
 
 SKSL_TEST(SkSLIntFoldingES3,                   "folding/IntFoldingES3.sksl")
diff --git a/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl b/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
index 96832b7..96479ba 100644
--- a/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
+++ b/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
@@ -5,8 +5,8 @@
 uniform vec4 uh4;
 uniform bool b;
 struct S {
-    vec4[1] ah4;
-    float[1] ah;
+    vec4 ah4[1];
+    float ah[1];
     vec4 h4;
     float h;
 };
diff --git a/tests/sksl/shared/Assignment.asm.frag b/tests/sksl/shared/Assignment.asm.frag
index f66558b..5c9be9d 100644
--- a/tests/sksl/shared/Assignment.asm.frag
+++ b/tests/sksl/shared/Assignment.asm.frag
@@ -15,6 +15,12 @@
 OpName %ai4 "ai4"
 OpName %ah2x4 "ah2x4"
 OpName %af4 "af4"
+OpName %S "S"
+OpMemberName %S 0 "f"
+OpMemberName %S 1 "af"
+OpMemberName %S 2 "h4"
+OpMemberName %S 3 "ah4"
+OpName %s "s"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
 OpDecorate %sk_FragColor Index 0
@@ -34,10 +40,20 @@
 OpDecorate %65 RelaxedPrecision
 OpDecorate %62 RelaxedPrecision
 OpDecorate %_arr_v4float_int_1 ArrayStride 16
-OpDecorate %87 RelaxedPrecision
-OpDecorate %94 RelaxedPrecision
-OpDecorate %95 RelaxedPrecision
-OpDecorate %98 RelaxedPrecision
+OpDecorate %_arr_float_int_5 ArrayStride 16
+OpDecorate %_arr_v4float_int_5 ArrayStride 16
+OpMemberDecorate %S 0 Offset 0
+OpMemberDecorate %S 1 Offset 16
+OpMemberDecorate %S 2 Offset 96
+OpMemberDecorate %S 2 RelaxedPrecision
+OpMemberDecorate %S 3 Offset 112
+OpMemberDecorate %S 3 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %92 RelaxedPrecision
+OpDecorate %108 RelaxedPrecision
+OpDecorate %115 RelaxedPrecision
+OpDecorate %116 RelaxedPrecision
+OpDecorate %122 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -87,6 +103,14 @@
 %_arr_v4float_int_1 = OpTypeArray %v4float %int_1
 %_ptr_Function__arr_v4float_int_1 = OpTypePointer Function %_arr_v4float_int_1
 %73 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+%int_5 = OpConstant %int 5
+%_arr_float_int_5 = OpTypeArray %float %int_5
+%_arr_v4float_int_5 = OpTypeArray %v4float %int_5
+%S = OpTypeStruct %float %_arr_float_int_5 %v4float %_arr_v4float_int_5
+%_ptr_Function_S = OpTypePointer Function %S
+%85 = OpConstantComposite %v3float %float_9 %float_9 %float_9
+%89 = OpConstantComposite %v2float %float_5 %float_5
+%102 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
 %_ptr_Function_v3float = OpTypePointer Function %v3float
 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %_entrypoint = OpFunction %void None %15
@@ -103,6 +127,7 @@
 %ai4 = OpVariable %_ptr_Function__arr_v4int_int_1 Function
 %ah2x4 = OpVariable %_ptr_Function__arr_mat3v3float_int_1 Function
 %af4 = OpVariable %_ptr_Function__arr_v4float_int_1 Function
+%s = OpVariable %_ptr_Function_S Function
 OpStore %i4 %28
 %32 = OpAccessChain %_ptr_Function_float %x %int_3
 OpStore %32 %float_0
@@ -126,29 +151,53 @@
 %75 = OpLoad %v4float %74
 %76 = OpVectorShuffle %v4float %75 %73 6 4 7 5
 OpStore %74 %76
-%77 = OpAccessChain %_ptr_Function_int %ai %int_0
-%78 = OpLoad %int %77
-%79 = OpAccessChain %_ptr_Function_v4int %ai4 %int_0
-%80 = OpLoad %v4int %79
-%81 = OpCompositeExtract %int %80 0
-%82 = OpIAdd %int %78 %81
-OpStore %77 %82
-%83 = OpAccessChain %_ptr_Function_v4float %af4 %int_0
-%84 = OpLoad %v4float %83
-%85 = OpAccessChain %_ptr_Function_v3float %ah2x4 %int_0 %int_0
-%87 = OpLoad %v3float %85
-%88 = OpCompositeExtract %float %87 0
-%89 = OpVectorTimesScalar %v4float %84 %88
-OpStore %83 %89
-%90 = OpAccessChain %_ptr_Function_int %i4 %int_1
-%91 = OpLoad %int %90
-%92 = OpIMul %int %91 %int_0
+%83 = OpAccessChain %_ptr_Function_float %s %int_0
+OpStore %83 %float_0
+%84 = OpAccessChain %_ptr_Function_float %s %int_1 %int_1
+OpStore %84 %float_0
+%86 = OpAccessChain %_ptr_Function_v4float %s %int_2
+%87 = OpLoad %v4float %86
+%88 = OpVectorShuffle %v4float %87 %85 5 6 4 3
+OpStore %86 %88
+%90 = OpAccessChain %_ptr_Function_v4float %s %int_3 %int_2
+%91 = OpLoad %v4float %90
+%92 = OpVectorShuffle %v4float %91 %89 0 4 2 5
 OpStore %90 %92
-%93 = OpAccessChain %_ptr_Function_float %x %int_1
-%94 = OpLoad %float %93
-%95 = OpFMul %float %94 %float_0
-OpStore %93 %95
-%96 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%98 = OpLoad %v4float %96
-OpReturnValue %98
+%93 = OpAccessChain %_ptr_Function_int %ai %int_0
+%94 = OpLoad %int %93
+%95 = OpAccessChain %_ptr_Function_v4int %ai4 %int_0
+%96 = OpLoad %v4int %95
+%97 = OpCompositeExtract %int %96 0
+%98 = OpIAdd %int %94 %97
+OpStore %93 %98
+%99 = OpAccessChain %_ptr_Function_float %s %int_0
+OpStore %99 %float_1
+%100 = OpAccessChain %_ptr_Function_float %s %int_1 %int_0
+OpStore %100 %float_2
+%101 = OpAccessChain %_ptr_Function_v4float %s %int_2
+OpStore %101 %73
+%103 = OpAccessChain %_ptr_Function_v4float %s %int_3 %int_0
+OpStore %103 %102
+%104 = OpAccessChain %_ptr_Function_v4float %af4 %int_0
+%105 = OpLoad %v4float %104
+%106 = OpAccessChain %_ptr_Function_v3float %ah2x4 %int_0 %int_0
+%108 = OpLoad %v3float %106
+%109 = OpCompositeExtract %float %108 0
+%110 = OpVectorTimesScalar %v4float %105 %109
+OpStore %104 %110
+%111 = OpAccessChain %_ptr_Function_int %i4 %int_1
+%112 = OpLoad %int %111
+%113 = OpIMul %int %112 %int_0
+OpStore %111 %113
+%114 = OpAccessChain %_ptr_Function_float %x %int_1
+%115 = OpLoad %float %114
+%116 = OpFMul %float %115 %float_0
+OpStore %114 %116
+%117 = OpAccessChain %_ptr_Function_float %s %int_0
+%118 = OpLoad %float %117
+%119 = OpFMul %float %118 %float_0
+OpStore %117 %119
+%120 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%122 = OpLoad %v4float %120
+OpReturnValue %122
 OpFunctionEnd
diff --git a/tests/sksl/shared/Assignment.glsl b/tests/sksl/shared/Assignment.glsl
index fe884e6..5f2fb97 100644
--- a/tests/sksl/shared/Assignment.glsl
+++ b/tests/sksl/shared/Assignment.glsl
@@ -1,6 +1,12 @@
 
 out vec4 sk_FragColor;
 uniform vec4 colorGreen;
+struct S {
+    float f;
+    float af[5];
+    vec4 h4;
+    vec4 ah4[5];
+};
 vec4 main() {
     ivec4 i4;
     i4 = ivec4(1, 2, 3, 4);
@@ -16,9 +22,19 @@
     vec4 af4[1];
     af4[0].x = 0.0;
     af4[0].ywxz = vec4(1.0);
+    S s;
+    s.f = 0.0;
+    s.af[1] = 0.0;
+    s.h4.zxy = vec3(9.0);
+    s.ah4[2].yw = vec2(5.0);
     ai[0] += ai4[0].x;
+    s.f = 1.0;
+    s.af[0] = 2.0;
+    s.h4 = vec4(1.0);
+    s.ah4[0] = vec4(2.0);
     af4[0] *= ah2x4[0][0].x;
     i4.y *= 0;
     x.y *= 0.0;
+    s.f *= 0.0;
     return colorGreen;
 }
diff --git a/tests/sksl/shared/Assignment.metal b/tests/sksl/shared/Assignment.metal
index e28e820..7a8d59a 100644
--- a/tests/sksl/shared/Assignment.metal
+++ b/tests/sksl/shared/Assignment.metal
@@ -1,6 +1,12 @@
 #include <metal_stdlib>
 #include <simd/simd.h>
 using namespace metal;
+struct S {
+    float f;
+    array<float, 5> af;
+    float4 h4;
+    array<float4, 5> ah4;
+};
 struct Uniforms {
     float4 colorGreen;
 };
@@ -27,10 +33,20 @@
     array<float4, 1> af4;
     af4[0].x = 0.0;
     af4[0].ywxz = float4(1.0);
+    S s;
+    s.f = 0.0;
+    s.af[1] = 0.0;
+    s.h4.zxy = float3(9.0);
+    s.ah4[2].yw = float2(5.0);
     ai[0] += ai4[0].x;
+    s.f = 1.0;
+    s.af[0] = 2.0;
+    s.h4 = float4(1.0);
+    s.ah4[0] = float4(2.0);
     af4[0] *= ah2x4[0][0].x;
     i4.y = i4.y * 0;
     x.y = x.y * 0.0;
+    s.f *= 0.0;
     _out.sk_FragColor = _uniforms.colorGreen;
     return _out;
 }
diff --git a/tests/sksl/shared/StructMaxDepth.glsl b/tests/sksl/shared/StructMaxDepth.glsl
index 0b3f753..d6ab111 100644
--- a/tests/sksl/shared/StructMaxDepth.glsl
+++ b/tests/sksl/shared/StructMaxDepth.glsl
@@ -25,27 +25,27 @@
 };
 in S8 s8;
 struct SA1 {
-    int[8] x;
+    int x[8];
 };
 struct SA2 {
-    SA1[7] x;
+    SA1 x[7];
 };
 struct SA3 {
-    SA2[6] x;
+    SA2 x[6];
 };
 struct SA4 {
-    SA3[5] x;
+    SA3 x[5];
 };
 struct SA5 {
-    SA4[4] x;
+    SA4 x[4];
 };
 struct SA6 {
-    SA5[3] x;
+    SA5 x[3];
 };
 struct SA7 {
-    SA6[2] x;
+    SA6 x[2];
 };
 struct SA8 {
-    SA7[1] x;
+    SA7 x[1];
 };
 in SA8 sa8[9];
diff --git a/tests/sksl/shared/Structs.glsl b/tests/sksl/shared/Structs.glsl
index 71b7630..07d907c 100644
--- a/tests/sksl/shared/Structs.glsl
+++ b/tests/sksl/shared/Structs.glsl
@@ -7,7 +7,7 @@
 A a1;
 struct B {
     float x;
-    float[2] y;
+    float y[2];
     layout (binding = 1) A z;
 };
 B b1;