Improve matrix construction abilities in Metal codegen.

GLSL (and thus SkSL) is flexible about the input parameters to a matrix
constructor. You can mix vectors and scalars freely, and it will
populate them into your matrix as if it was a flat list of scalars.

Metal does not natively support this, and requires the proper number of
floatNs to be passed in. However, the Metal code generator will now emit
constructor helper functions that will fix this up automatically.

Additionally, this CL simplifies the Metal codegen for single-scalar
matrix construction. This should create a matrix with the passed-in
scalar running along the matrix diagonal. The Metal codegen previously
emitted a helper function to do this work on our behalf. However,
that's not necessary; Metal already contains a single-argument matrix
constructor that will do this work automatically for us.

Change-Id: I76901bfe167502797aa4cb98d0e8986d9ebc51e5
Bug: skia:10280
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292477
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/tests/SkSLMetalTest.cpp b/tests/SkSLMetalTest.cpp
index 13cecb9..a8640ba 100644
--- a/tests/SkSLMetalTest.cpp
+++ b/tests/SkSLMetalTest.cpp
@@ -60,54 +60,104 @@
          "}\n");
 }
 
+DEF_TEST(SkSLMetal2x2MatrixCopyFromFloat2x2, r) {
+    test(r, R"__SkSL__(
+void main() {
+  float2x2 m1 = float2x2(float2(1, 2), float2(3, 4));
+  float2x2 m2 = m1;
+  float2x2 m3 = float2x2(m1);
+  sk_FragColor = half4(half(m1[0][0] + m2[0][0] + m3[0][0]));
+})__SkSL__",
+             *SkSL::ShaderCapsFactory::Default(),
+    R"__MSL__(#include <metal_stdlib>
+#include <simd/simd.h>
+using namespace metal;
+struct Inputs {
+};
+struct Outputs {
+    float4 sk_FragColor [[color(0)]];
+};
+fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+    Outputs _outputStruct;
+    thread Outputs* _out = &_outputStruct;
+    _out->sk_FragColor = float4((float2x2(float2(1.0, 2.0), float2(3.0, 4.0))[0][0] + float2x2(float2(1.0, 2.0), float2(3.0, 4.0))[0][0]) + float2x2(float2(1.0, 2.0), float2(3.0, 4.0))[0][0]);
+    return *_out;
+}
+)__MSL__");
+}
+
+DEF_TEST(SkSLMetal2x2MatrixCopyFromConstantPropagatedFloat4, r) {
+    test(r, R"__SkSL__(
+void main() {
+  float2x2 m1 = float2x2(float4(1, 2, 3, 4));
+  float2x2 m2 = m1;
+  float2x2 m3 = float2x2(m1);
+  sk_FragColor = half4(half(m1[0][0] + m2[0][0] + m3[0][0]));
+})__SkSL__",
+             *SkSL::ShaderCapsFactory::Default(),
+R"__MSL__(#include <metal_stdlib>
+#include <simd/simd.h>
+using namespace metal;
+struct Inputs {
+};
+struct Outputs {
+    float4 sk_FragColor [[color(0)]];
+};
+float2x2 float2x2_from_float4(float4 x0) {
+    return float2x2(float2(x0[0], x0[1]), float2(x0[2], x0[3]));
+}
+fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+    Outputs _outputStruct;
+    thread Outputs* _out = &_outputStruct;
+    _out->sk_FragColor = float4((float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0] + float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0]) + float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0]);
+    return *_out;
+}
+)__MSL__");
+}
+
 DEF_TEST(SkSLMetalMatrices, r) {
-    test(r,
-         "void main() {"
-         "float2x2 m1 = float2x2(float4(1, 2, 3, 4));"
-         "float2x2 m2 = float2x2(float4(0));"
-         "float2x2 m3 = float2x2(m1);"
-         "float2x2 m4 = float2x2(1);"
-         "float2x2 m5 = float2x2(m1[0][0]);"
-         "float2x2 m6 = float2x2(1, 2, 3, 4);"
-         "float2x2 m7 = float2x2(5, 6, 7, 8);"
-         "float3x3 m8 = float3x3(1);"
-         "float3x3 m9 = float3x3(2);"
-         "float4x4 m10 = float4x4(1);"
-         "float4x4 m11 = float4x4(2);"
-         "sk_FragColor = half4(half(m1[0][0] + m2[0][0] + m3[0][0] + m4[0][0] + m5[0][0] + "
-                "m6[0][0] + m7[0][0] + m8[0][0] + m9[0][0] + m10[0][0] + m11[0][0]));"
-         "}",
+    test(r, R"__SkSL__(
+void main() {
+  float2x2 m1 = float2x2(float4(1, 2, 3, 4));
+  float2x2 m2 = float2x2(float4(0));
+  float2x2 m3 = float2x2(m1);
+  float2x2 m4 = float2x2(1);
+  float2x2 m5 = float2x2(m1[0][0]);
+  float2x2 m6 = float2x2(1, 2, 3, 4);
+  float2x2 m7 = float2x2(5, float3(6, 7, 8));
+  float3x2 m8 = float3x2(float2(1, 2), 3, float3(4, 5, 6));
+  float3x3 m9 = float3x3(1);
+  float4x4 m10 = float4x4(1);
+  float4x4 m11 = float4x4(2);
+  sk_FragColor = half4(half(m1[0][0] + m2[0][0] + m3[0][0] + m4[0][0] + m5[0][0] +
+                            m6[0][0] + m7[0][0] + m8[0][0] + m9[0][0] + m10[0][0] + m11[0][0]));
+})__SkSL__",
          *SkSL::ShaderCapsFactory::Default(),
-         "#include <metal_stdlib>\n"
-         "#include <simd/simd.h>\n"
-         "using namespace metal;\n"
-         "struct Inputs {\n"
-         "};\n"
-         "struct Outputs {\n"
-         "    float4 sk_FragColor [[color(0)]];\n"
-         "};\n"
-         "float2x2 float2x2_from_float(float x) {\n"
-         "    return float2x2(float2(x, 0), float2(0, x));\n"
-         "}\n"
-         "float2x2 float2x2_from_float4(float4 v) {\n"
-         "    return float2x2(float2(v[0], v[1]), float2(v[2], v[3]));\n"
-         "}\n"
-         "float2x2 float2x2_from_float(float x) {\n"
-         "    return float2x2(float2(x, 0), float2(0, x));\n"
-         "}\n"
-         "float3x3 float3x3_from_float(float x) {\n"
-         "    return float3x3(float3(x, 0, 0), float3(0, x, 0), float3(0, 0, x));\n"
-         "}\n"
-         "float4x4 float4x4_from_float(float x) {\n"
-         "    return float4x4(float4(x, 0, 0, 0), float4(0, x, 0, 0), float4(0, 0, x, 0), float4(0, 0, 0, x));\n"
-         "}\n"
-         "fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {\n"
-         "    Outputs _outputStruct;\n"
-         "    thread Outputs* _out = &_outputStruct;\n"
-         "    float2x2 m5 = float2x2_from_float(float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0]);\n"
-         "    _out->sk_FragColor = float4((((((((((float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0] + float2x2_from_float4(float4(0.0))[0][0]) + float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0]) + float2x2_from_float(1.0)[0][0]) + m5[0][0]) + float2x2(float2(1.0, 2.0), float2(3.0, 4.0))[0][0]) + float2x2(float2(5.0, 6.0), float2(7.0, 8.0))[0][0]) + float3x3_from_float(1.0)[0][0]) + float3x3_from_float(2.0)[0][0]) + float4x4_from_float(1.0)[0][0]) + float4x4_from_float(2.0)[0][0]);\n"
-         "    return *_out;\n"
-         "}\n");
+R"__MSL__(#include <metal_stdlib>
+#include <simd/simd.h>
+using namespace metal;
+struct Inputs {
+};
+struct Outputs {
+    float4 sk_FragColor [[color(0)]];
+};
+float2x2 float2x2_from_float4(float4 x0) {
+    return float2x2(float2(x0[0], x0[1]), float2(x0[2], x0[3]));
+}
+float2x2 float2x2_from_float_float3(float x0, float3 x1) {
+    return float2x2(float2(x0, x1[0]), float2(x1[1], x1[2]));
+}
+float3x2 float3x2_from_float2_float_float3(float2 x0, float x1, float3 x2) {
+    return float3x2(float2(x0[0], x0[1]), float2(x1, x2[0]), float2(x2[1], x2[2]));
+}
+fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
+    Outputs _outputStruct;
+    thread Outputs* _out = &_outputStruct;
+    float2x2 m5 = float2x2(float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0]);
+    _out->sk_FragColor = float4((((((((((float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0] + float2x2_from_float4(float4(0.0))[0][0]) + float2x2_from_float4(float4(1.0, 2.0, 3.0, 4.0))[0][0]) + float2x2(1.0)[0][0]) + m5[0][0]) + float2x2(float2(1.0, 2.0), float2(3.0, 4.0))[0][0]) + float2x2_from_float_float3(5.0, float3(6.0, 7.0, 8.0))[0][0]) + float3x2_from_float2_float_float3(float2(1.0, 2.0), 3.0, float3(4.0, 5.0, 6.0))[0][0]) + float3x3(1.0)[0][0]) + float4x4(1.0)[0][0]) + float4x4(2.0)[0][0]);
+    return *_out;
+}
+)__MSL__");
 }
 
 DEF_TEST(SkSLMetalConstantSwizzle, r) {