Support variables in the intrinsic map, clone them into Programs

As a first step, convert sksl_pipeline.sksl to an IntrinsicMap (rather
than inherited element list). This makes the new code operate on
sk_FragCoord (which was previously being shared by all runtime effect
programs).

The new unit test angered TSAN, and now runs without complaint.

Also finish converting the .fp intrinsics over, so those don't need an
inherited element list either. And while doing that, refactor that
parsing to match all of the others. FP was uniquely implementing
processIncludeFile itself, rather than reusing the pattern of other
pre-include parsing.

The meat of the CL is the subtle changes in Compiler, and the logic in
cloneBuiltinVariables. Note that we need to clone the global variable
declaration element (because one of the goals is to get rid of shared
and inherited program elements), but also the variable itself (and the
new copy needs to live in the program's symbol table).

Bug: skia:10589
Bug: skia:10679
Bug: skia:10680
Change-Id: Ied352f8434dac2b8eacb4e515b014b6af7b57d20
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319023
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 0f91c0b..4d788cc 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -18,6 +18,7 @@
 #include "tests/Test.h"
 
 #include <algorithm>
+#include <thread>
 
 DEF_TEST(SkRuntimeEffectInvalid, r) {
     auto test = [r](const char* hdr, const char* body, const char* expected) {
@@ -289,3 +290,23 @@
     b.uniform("x") = 1.0f;
     auto shader_1 = b.makeShader(nullptr, true);
 }
+
+DEF_TEST(SkRuntimeEffectThreaded, r) {
+    // SkRuntimeEffect uses a single compiler instance, but it's mutex locked.
+    // This tests that we can safely use it from more than one thread, and also
+    // that programs don't refer to shared structures owned by the compiler.
+    // skbug.com/10589
+    static constexpr char kSource[] = "half4 main() { return sk_FragCoord.xyxy; }";
+
+    std::thread threads[16];
+    for (auto& thread : threads) {
+        thread = std::thread([r]() {
+            auto [effect, error] = SkRuntimeEffect::Make(SkString(kSource));
+            REPORTER_ASSERT(r, effect);
+        });
+    }
+
+    for (auto& thread : threads) {
+        thread.join();
+    }
+}