Make SkRuntimeEffect's compiler instance shareable.

No functional change.

Bug: skia:12720
Change-Id: I649bc258c9a6b4973cdd9d1727827cdaf89b43ad
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/481280
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 74cb2c2..e9062cb 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -73,6 +73,8 @@
   "$_src/sksl/SkSLRehydrator.cpp",
   "$_src/sksl/SkSLRehydrator.h",
   "$_src/sksl/SkSLSampleUsage.cpp",
+  "$_src/sksl/SkSLSharedCompiler.cpp",
+  "$_src/sksl/SkSLSharedCompiler.h",
   "$_src/sksl/SkSLString.cpp",
   "$_src/sksl/SkSLStringStream.h",
   "$_src/sksl/SkSLThreadContext.cpp",
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index 606baeb..30e62b4 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -5,10 +5,11 @@
  * found in the LICENSE file.
  */
 
+#include "include/effects/SkRuntimeEffect.h"
+
 #include "include/core/SkColorFilter.h"
 #include "include/core/SkData.h"
 #include "include/core/SkSurface.h"
-#include "include/effects/SkRuntimeEffect.h"
 #include "include/private/SkMutex.h"
 #include "src/core/SkBlenderBase.h"
 #include "src/core/SkCanvasPriv.h"
@@ -26,6 +27,7 @@
 #include "src/core/SkWriteBuffer.h"
 #include "src/sksl/SkSLAnalysis.h"
 #include "src/sksl/SkSLCompiler.h"
+#include "src/sksl/SkSLSharedCompiler.h"
 #include "src/sksl/SkSLUtil.h"
 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
 #include "src/sksl/codegen/SkVMDebugTrace.h"
@@ -50,61 +52,6 @@
 
 #ifdef SK_ENABLE_SKSL
 
-namespace SkSL {
-class SharedCompiler {
-public:
-    SharedCompiler() : fLock(compiler_mutex()) {
-        if (!gImpl) {
-            gImpl = new Impl();
-        }
-    }
-
-    SkSL::Compiler* operator->() const { return gImpl->fCompiler; }
-
-private:
-    SkAutoMutexExclusive fLock;
-
-    static SkMutex& compiler_mutex() {
-        static SkMutex& mutex = *(new SkMutex);
-        return mutex;
-    }
-
-    struct Impl {
-        Impl() {
-            // These caps are configured to apply *no* workarounds. This avoids changes that are
-            // unnecessary (GLSL intrinsic rewrites), or possibly incorrect (adding do-while loops).
-            // We may apply other "neutral" transformations to the user's SkSL, including inlining.
-            // Anything determined by the device caps is deferred to the GPU backend. The processor
-            // set produces the final program (including our re-emitted SkSL), and the backend's
-            // compiler resolves any necessary workarounds.
-            fCaps = ShaderCapsFactory::Standalone();
-            fCaps->fBuiltinFMASupport = true;
-            fCaps->fBuiltinDeterminantSupport = true;
-            // Don't inline if it would require a do loop, some devices don't support them.
-            fCaps->fCanUseDoLoops = false;
-
-            // SkSL created by the GPU backend is typically parsed, converted to a backend format,
-            // and the IR is immediately discarded. In that situation, it makes sense to use node
-            // pools to accelerate the IR allocations. Here, SkRuntimeEffect instances are often
-            // long-lived (especially those created internally for runtime FPs). In this situation,
-            // we're willing to pay for a slightly longer compile so that we don't waste huge
-            // amounts of memory.
-            fCaps->fUseNodePools = false;
-
-            fCompiler = new SkSL::Compiler(fCaps.get());
-        }
-
-        std::unique_ptr<SkSL::ShaderCaps> fCaps;
-        SkSL::Compiler*                   fCompiler;
-    };
-
-    static Impl* gImpl;
-};
-
-SharedCompiler::Impl* SharedCompiler::gImpl = nullptr;
-
-}  // namespace SkSL
-
 static sk_sp<SkSL::SkVMDebugTrace> make_skvm_debug_trace(SkRuntimeEffect* effect,
                                                          const SkIPoint& coord) {
     auto debugTrace = sk_make_sp<SkSL::SkVMDebugTrace>();
diff --git a/src/sksl/SkSLSharedCompiler.cpp b/src/sksl/SkSLSharedCompiler.cpp
new file mode 100644
index 0000000..b27e0bf
--- /dev/null
+++ b/src/sksl/SkSLSharedCompiler.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/sksl/SkSLSharedCompiler.h"
+
+#ifdef SK_ENABLE_SKSL
+
+namespace SkSL {
+struct SharedCompiler::Impl {
+    Impl() {
+        // These caps are configured to apply *no* workarounds. This avoids changes that are
+        // unnecessary (GLSL intrinsic rewrites), or possibly incorrect (adding do-while loops).
+        // We may apply other "neutral" transformations to the user's SkSL, including inlining.
+        // Anything determined by the device caps is deferred to the GPU backend. The processor
+        // set produces the final program (including our re-emitted SkSL), and the backend's
+        // compiler resolves any necessary workarounds.
+        fCaps = ShaderCapsFactory::Standalone();
+        fCaps->fBuiltinFMASupport = true;
+        fCaps->fBuiltinDeterminantSupport = true;
+        // Don't inline if it would require a do loop, some devices don't support them.
+        fCaps->fCanUseDoLoops = false;
+
+        // SkSL created by the GPU backend is typically parsed, converted to a backend format,
+        // and the IR is immediately discarded. In that situation, it makes sense to use node
+        // pools to accelerate the IR allocations. Here, SkRuntimeEffect instances are often
+        // long-lived (especially those created internally for runtime FPs). In this situation,
+        // we're willing to pay for a slightly longer compile so that we don't waste huge
+        // amounts of memory.
+        fCaps->fUseNodePools = false;
+
+        fCompiler = new SkSL::Compiler(fCaps.get());
+    }
+
+    std::unique_ptr<SkSL::ShaderCaps> fCaps;
+    SkSL::Compiler*                   fCompiler;
+};
+
+SharedCompiler::Impl* SharedCompiler::gImpl = nullptr;
+
+SharedCompiler::SharedCompiler() : fLock(compiler_mutex()) {
+    if (!gImpl) {
+        gImpl = new Impl();
+    }
+}
+
+SkSL::Compiler* SharedCompiler::operator->() const { return gImpl->fCompiler; }
+
+SkMutex& SharedCompiler::compiler_mutex() {
+    static SkMutex& mutex = *(new SkMutex);
+    return mutex;
+}
+
+}  // namespace SkSL
+
+#endif
diff --git a/src/sksl/SkSLSharedCompiler.h b/src/sksl/SkSLSharedCompiler.h
new file mode 100644
index 0000000..7eb667e
--- /dev/null
+++ b/src/sksl/SkSLSharedCompiler.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSLSharedCompiler_DEFINED
+#define SkSLSharedCompiler_DEFINED
+
+#include "include/private/SkMutex.h"
+#include "src/sksl/SkSLCompiler.h"
+
+#ifdef SK_ENABLE_SKSL
+
+namespace SkSL {
+
+/** A shared compiler instance for runtime client SkSL that is internally guarded by a mutex. */
+class SharedCompiler {
+public:
+    SharedCompiler();
+
+    SkSL::Compiler* operator->() const;
+
+private:
+    SkAutoMutexExclusive fLock;
+
+    static SkMutex& compiler_mutex();
+
+    struct Impl;
+    static Impl* gImpl;
+};
+
+}  // namespace SkSL
+
+#endif  // SK_ENABLE_SKSL
+
+#endif