Reland "Fix array-of-matrix/struct comparisons in Metal."

This is a reland of 23d8f94535813d7c973af69aaeb67a0e5d7c9140

Original change's description:
> Fix array-of-matrix/struct comparisons in Metal.
>
> Metal needs helper functions in order to compare arrays, structs, and
> matrices. Depending on the input code, it was possible for the
> array-comparison helper to be emitted before a matrix-comparison
> or struct-comparison helper. If this occurred, array comparisons of that
> matrix or struct type would fail, because the operator== for the array's
> inner type was defined after array==, and Metal (like C++) parses
> top-to-bottom and only considers functions declared above the current
> function.
>
> We now emit prototypes for all the array, struct and matrix helper
> function. These prototypes are emitted above any helper functions. This
> ensures visibility no matter how your comparisons are organized.
>
> Change-Id: Ib3d8828c301fd0fa6c209788f9ea60800371edbe
> Bug: skia:12326
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/437739
> Commit-Queue: John Stiles <johnstiles@google.com>
> Auto-Submit: John Stiles <johnstiles@google.com>
> Reviewed-by: Brian Osman <brianosman@google.com>

Bug: skia:12326
Change-Id: Ife68020f6b01fae973b97f76099c6d5e8215636c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438296
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
index 1cb0053..b39ee1c 100644
--- a/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
+++ b/src/sksl/codegen/SkSLMetalCodeGenerator.cpp
@@ -1287,6 +1287,15 @@
 
     auto [iter, wasInserted] = fHelpers.insert(key);
     if (wasInserted) {
+        fExtraFunctionPrototypes.printf(R"(
+thread bool operator==(const %s left, const %s right);
+thread bool operator!=(const %s left, const %s right);
+)",
+                                        this->typeName(left).c_str(),
+                                        this->typeName(right).c_str(),
+                                        this->typeName(left).c_str(),
+                                        this->typeName(right).c_str());
+
         fExtraFunctions.printf(
                 "thread bool operator==(const %s left, const %s right) {\n"
                 "    return ",
@@ -1346,6 +1355,12 @@
 
     auto [iter, wasInserted] = fHelpers.insert("ArrayEquality []");
     if (wasInserted) {
+        fExtraFunctionPrototypes.writeText(R"(
+template <typename T1, typename T2, size_t N>
+bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right);
+template <typename T1, typename T2, size_t N>
+bool operator!=(thread const array<T1, N>& left, thread const array<T2, N>& right);
+)");
         fExtraFunctions.writeText(R"(
 template <typename T1, typename T2, size_t N>
 bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) {
@@ -1378,6 +1393,15 @@
 
         // Write operator== and operator!= for this struct, since those are assumed to exist in SkSL
         // and GLSL but do not exist by default in Metal.
+        fExtraFunctionPrototypes.printf(R"(
+thread bool operator==(thread const %s& left, thread const %s& right);
+thread bool operator!=(thread const %s& left, thread const %s& right);
+)",
+                                        this->typeName(type).c_str(),
+                                        this->typeName(type).c_str(),
+                                        this->typeName(type).c_str(),
+                                        this->typeName(type).c_str());
+
         fExtraFunctions.printf(
                 "thread bool operator==(thread const %s& left, thread const %s& right) {\n"
                 "    return ",
@@ -2573,6 +2597,7 @@
         }
     }
     write_stringstream(header, *fOut);
+    write_stringstream(fExtraFunctionPrototypes, *fOut);
     write_stringstream(fExtraFunctions, *fOut);
     write_stringstream(body, *fOut);
     return 0 == fErrors.errorCount();