Add SkSLCompiler::toHLSL, using SPIRV-Cross

Change-Id: Ia7a11a726cac006f6acc36efe8fc2ff27f30af72
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/270837
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 0acc43e..dd72563 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -444,6 +444,7 @@
     include_dirs = [ "." ]
     deps = [
       ":run_sksllex",
+      "//third_party/spirv-cross:spirv_cross",
       "//third_party/spirv-tools:spvtools",
     ]
   }
@@ -511,6 +512,7 @@
   deps = [
     ":compile_processors",
     ":run_sksllex",
+    "//third_party/spirv-cross:spirv_cross",
   ]
   if (skia_generate_workarounds) {
     deps += [ ":workaround_list" ]
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 182d312..a692166 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -32,6 +32,7 @@
   "$_src/sksl/SkSLOutputStream.cpp",
   "$_src/sksl/SkSLPipelineStageCodeGenerator.cpp",
   "$_src/sksl/SkSLSPIRVCodeGenerator.cpp",
+  "$_src/sksl/SkSLSPIRVtoHLSL.cpp",
 ]
 
 skia_gpu_processor_sources = [
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index de8b735..92c0c03 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -16,6 +16,7 @@
 #include "src/sksl/SkSLMetalCodeGenerator.h"
 #include "src/sksl/SkSLPipelineStageCodeGenerator.h"
 #include "src/sksl/SkSLSPIRVCodeGenerator.h"
+#include "src/sksl/SkSLSPIRVtoHLSL.h"
 #include "src/sksl/ir/SkSLEnum.h"
 #include "src/sksl/ir/SkSLExpression.h"
 #include "src/sksl/ir/SkSLExpressionStatement.h"
@@ -1562,6 +1563,15 @@
     return result;
 }
 
+bool Compiler::toHLSL(Program& program, String* out) {
+    String spirv;
+    if (!this->toSPIRV(program, &spirv)) {
+        return false;
+    }
+
+    return SPIRVtoHLSL(spirv, out);
+}
+
 bool Compiler::toMetal(Program& program, OutputStream& out) {
     if (!this->optimize(program)) {
         return false;
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 7eaba35..6aebb78 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -135,6 +135,8 @@
 
     bool toGLSL(Program& program, String* out);
 
+    bool toHLSL(Program& program, String* out);
+
     bool toMetal(Program& program, OutputStream& out);
 
     bool toMetal(Program& program, String* out);
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index b8009cd..eba5d1d 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -95,6 +95,24 @@
             printf("error writing '%s'\n", argv[2]);
             exit(4);
         }
+    } else if (name.endsWith(".hlsl")) {
+        SkSL::FileOutputStream out(argv[2]);
+        SkSL::Compiler compiler;
+        if (!out.isValid()) {
+            printf("error writing '%s'\n", argv[2]);
+            exit(4);
+        }
+        std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, text, settings);
+        SkSL::String hlsl;
+        if (!program || !compiler.toHLSL(*program, &hlsl)) {
+            printf("%s", compiler.errorText().c_str());
+            exit(3);
+        }
+        out.writeString(hlsl);
+        if (!out.close()) {
+            printf("error writing '%s'\n", argv[2]);
+            exit(4);
+        }
     } else if (name.endsWith(".metal")) {
         SkSL::FileOutputStream out(argv[2]);
         SkSL::Compiler compiler;
diff --git a/src/sksl/SkSLSPIRVtoHLSL.cpp b/src/sksl/SkSLSPIRVtoHLSL.cpp
new file mode 100644
index 0000000..1561497
--- /dev/null
+++ b/src/sksl/SkSLSPIRVtoHLSL.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 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/SkSLSPIRVtoHLSL.h"
+
+#if __has_include("third_party/externals/spirv-cross/spirv_hlsl.hpp")
+
+#include "third_party/externals/spirv-cross/spirv_hlsl.hpp"
+
+/*
+ * This translation unit serves as a bridge between Skia/SkSL and SPIRV-Cross.
+ * Each library is built with a separate copy of spirv.h (or spirv.hpp), so we
+ * avoid conflicts by never including both in the same cpp.
+ */
+
+namespace SkSL {
+
+bool SPIRVtoHLSL(const String& spirv, String* hlsl) {
+    spirv_cross::CompilerHLSL hlslCompiler((const uint32_t*)spirv.c_str(),
+                                           spirv.size() / sizeof(uint32_t));
+    hlsl->assign(hlslCompiler.compile());
+    return true;
+}
+
+}
+
+#else
+
+namespace SkSL { bool SPIRVtoHLSL(const String&, String*) { return false; } }
+
+#endif
diff --git a/src/sksl/SkSLSPIRVtoHLSL.h b/src/sksl/SkSLSPIRVtoHLSL.h
new file mode 100644
index 0000000..2823813
--- /dev/null
+++ b/src/sksl/SkSLSPIRVtoHLSL.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_SPIRVTOHLSL
+#define SKSL_SPIRVTOHLSL
+
+#include "src/sksl/SkSLString.h"
+
+namespace SkSL {
+
+bool SPIRVtoHLSL(const String& spirv, String* hlsl);
+
+}
+
+#endif