Improve support for function prototypes in SkSL.

Previously, when a prototype was parsed, this added a function
declaration to the symbol table, but the prototype itself was not
re-emitted during code generation. This meant that the final code might
not be valid, since the absence of prototypes meant that the code might
attempt to invoke a function before its declaration. Now, prototypes are
stored in the ProgramElement list and re-emitted during code generation
for GLSL/Metal/CPP. (SPIR-V doesn't name its functions at all.)

Change-Id: I76446c796000eb0b56f964d82457122182c28b87
Bug: skia:10872
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/331136
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/SkSLDehydrator.cpp b/src/sksl/SkSLDehydrator.cpp
index 18adbc3..6b81f28 100644
--- a/src/sksl/SkSLDehydrator.cpp
+++ b/src/sksl/SkSLDehydrator.cpp
@@ -541,6 +541,12 @@
             }
             break;
         }
+        case ProgramElement::Kind::kFunctionPrototype: {
+            // We don't need to emit function prototypes into the dehydrated data, because we don't
+            // ever need to re-emit the intrinsics files as raw GLSL/Metal. As long as the symbols
+            // exist in the symbol table, we're in good shape.
+            break;
+        }
         case ProgramElement::Kind::kInterfaceBlock: {
             const InterfaceBlock& i = e.as<InterfaceBlock>();
             this->writeCommand(Rehydrator::kInterfaceBlock_Command);