From 271347ad0205e6ea206cfc01e04b4fe1d1165d8c Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Sat, 13 Jan 2024 01:47:24 +0100
Subject: [PATCH] Implement separate compiler classes for LLVM and slim
 front-ends

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 modules/shader_compiler/CMakeLists.txt        |   6 +
 .../include/vkcv/shader/GlslangCompiler.hpp   |   2 -
 .../include/vkcv/shader/LLVMCompiler.hpp      |  53 ++++++++
 .../include/vkcv/shader/ShadyCompiler.hpp     |  55 +++++++-
 .../include/vkcv/shader/SlimCompiler.hpp      |  53 ++++++++
 .../src/vkcv/shader/LLVMCompiler.cpp          | 119 +++++++++++++++++
 .../src/vkcv/shader/ShadyCompiler.cpp         | 126 +++---------------
 .../src/vkcv/shader/SlimCompiler.cpp          | 119 +++++++++++++++++
 8 files changed, 417 insertions(+), 116 deletions(-)
 create mode 100644 modules/shader_compiler/include/vkcv/shader/LLVMCompiler.hpp
 create mode 100644 modules/shader_compiler/include/vkcv/shader/SlimCompiler.hpp
 create mode 100644 modules/shader_compiler/src/vkcv/shader/LLVMCompiler.cpp
 create mode 100644 modules/shader_compiler/src/vkcv/shader/SlimCompiler.cpp

diff --git a/modules/shader_compiler/CMakeLists.txt b/modules/shader_compiler/CMakeLists.txt
index 35b31192..960eb65c 100644
--- a/modules/shader_compiler/CMakeLists.txt
+++ b/modules/shader_compiler/CMakeLists.txt
@@ -24,6 +24,12 @@ set(vkcv_shader_compiler_sources
 
 		${vkcv_shader_compiler_include}/vkcv/shader/ShadyCompiler.hpp
 		${vkcv_shader_compiler_source}/vkcv/shader/ShadyCompiler.cpp
+
+		${vkcv_shader_compiler_include}/vkcv/shader/SlimCompiler.hpp
+		${vkcv_shader_compiler_source}/vkcv/shader/SlimCompiler.cpp
+
+		${vkcv_shader_compiler_include}/vkcv/shader/LLVMCompiler.hpp
+		${vkcv_shader_compiler_source}/vkcv/shader/LLVMCompiler.cpp
 )
 
 filter_headers(vkcv_shader_compiler_sources ${vkcv_shader_compiler_include} vkcv_shader_compiler_headers)
diff --git a/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp
index 837b9b1d..161c796e 100644
--- a/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/GlslangCompiler.hpp
@@ -19,8 +19,6 @@ namespace vkcv::shader {
 	public:
 		/**
 		 * The constructor of a runtime Glslang shader compiler instance.
-		 *
-		 * @param[in] target Compile target (optional)
 		 */
 		GlslangCompiler();
 		
diff --git a/modules/shader_compiler/include/vkcv/shader/LLVMCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/LLVMCompiler.hpp
new file mode 100644
index 00000000..2d075d7b
--- /dev/null
+++ b/modules/shader_compiler/include/vkcv/shader/LLVMCompiler.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <filesystem>
+
+#include <vkcv/ShaderStage.hpp>
+#include "ShadyCompiler.hpp"
+
+namespace vkcv::shader {
+	
+	/**
+	 * @addtogroup vkcv_shader
+	 * @{
+	 */
+	
+	enum class LLVMCompileTarget {
+		UNKNOWN
+	};
+	
+	/**
+	 * A class to handle LLVM runtime shader compilation.
+	 */
+	class LLVMCompiler : public ShadyCompiler {
+	private:
+		LLVMCompileTarget m_target;
+	
+	public:
+		/**
+		 * The constructor of a runtime LLVM shader compiler instance.
+		 *
+		 * @param[in] target Compile target (optional)
+		 */
+		explicit LLVMCompiler(LLVMCompileTarget target = LLVMCompileTarget::UNKNOWN);
+		
+		/**
+		 * Compile a LLVM shader from source for a target stage with a custom shader
+		 * include path and an event function called if the compilation completes.
+		 *
+		 * @param[in] shaderStage Shader pipeline stage
+		 * @param[in] shaderSource Source of shader
+		 * @param[in] compiled Shader compilation event
+		 * @param[in] includePath Include path for shaders
+		 * @return Result if the compilation succeeds
+		 */
+		bool compileSource(ShaderStage shaderStage,
+						   const std::string& shaderSource,
+						   const ShaderCompiledFunction& compiled,
+						   const std::filesystem::path& includePath = "") override;
+		
+	};
+	
+	/** @} */
+	
+}
diff --git a/modules/shader_compiler/include/vkcv/shader/ShadyCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/ShadyCompiler.hpp
index 181d30da..65e732f0 100644
--- a/modules/shader_compiler/include/vkcv/shader/ShadyCompiler.hpp
+++ b/modules/shader_compiler/include/vkcv/shader/ShadyCompiler.hpp
@@ -7,20 +7,67 @@
 
 namespace vkcv::shader {
 
+    /**
+     * @addtogroup vkcv_shader
+     * @{
+     */
+
+    /**
+	 * An abstract class to handle Shady runtime shader compilation.
+	 */
     class ShadyCompiler : public Compiler {
     public:
+        /**
+		 * The constructor of a runtime Shady shader compiler instance.
+		 */
         ShadyCompiler();
 
-        ShadyCompiler(const ShadyCompiler& other);
+        /**
+		 * The copy-constructor of a runtime Shady shader compiler instance.
+		 *
+		 * @param[in] other Other instance of a Shady shader compiler instance
+		 */
+        ShadyCompiler(const ShadyCompiler& other) = default;
 
+        /**
+		 * The move-constructor of a runtime Shady shader compiler instance.
+		 *
+		 * @param[out] other Other instance of a Shady shader compiler instance
+		 */
         ShadyCompiler(ShadyCompiler&& other) = default;
 
-        ~ShadyCompiler();
+        /**
+		 * The destructor of a runtime Shady shader compiler instance.
+		 */
+        ~ShadyCompiler() = default;
 
-        ShadyCompiler& operator=(const ShadyCompiler& other);
+        /**
+		 * The copy-operator of a runtime Shady shader compiler instance.
+		 *
+		 * @param[in] other Other instance of a Shady shader compiler instance
+		 * @return Reference to this instance
+		 */
+        ShadyCompiler& operator=(const ShadyCompiler& other) = default;
 
+        /**
+		 * The copy-operator of a runtime Shady shader compiler instance.
+		 *
+		 * @param[out] other Other instance of a Shady shader compiler instance
+		 * @return Reference to this instance
+		 */
         ShadyCompiler& operator=(ShadyCompiler&& other) = default;
 
+        /**
+         * Compile a shader from a specific file path for a target stage with
+         * a custom shader include path and an event function called if the
+         * compilation completes.
+         *
+         * @param[in] shaderStage Shader pipeline stage
+         * @param[in] shaderPath Filepath of shader
+         * @param[in] compiled Shader compilation event
+         * @param[in] includePath Include path for shaders
+         * @param[in] update Flag to update shaders during runtime
+         */
         void compile(ShaderStage shaderStage,
 					 const std::filesystem::path& shaderPath,
 					 const ShaderCompiledFunction& compiled,
@@ -29,4 +76,6 @@ namespace vkcv::shader {
 
     };
 
+    /** @} */
+
 }
diff --git a/modules/shader_compiler/include/vkcv/shader/SlimCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/SlimCompiler.hpp
new file mode 100644
index 00000000..47d9596e
--- /dev/null
+++ b/modules/shader_compiler/include/vkcv/shader/SlimCompiler.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <filesystem>
+
+#include <vkcv/ShaderStage.hpp>
+#include "ShadyCompiler.hpp"
+
+namespace vkcv::shader {
+	
+	/**
+	 * @addtogroup vkcv_shader
+	 * @{
+	 */
+	
+	enum class SlimCompileTarget {
+		UNKNOWN
+	};
+	
+	/**
+	 * A class to handle Slim runtime shader compilation.
+	 */
+	class SlimCompiler : public ShadyCompiler {
+	private:
+		SlimCompileTarget m_target;
+	
+	public:
+		/**
+		 * The constructor of a runtime Slim shader compiler instance.
+		 *
+		 * @param[in] target Compile target (optional)
+		 */
+		explicit SlimCompiler(SlimCompileTarget target = SlimCompileTarget::UNKNOWN);
+		
+		/**
+		 * Compile a Slim shader from source for a target stage with a custom shader
+		 * include path and an event function called if the compilation completes.
+		 *
+		 * @param[in] shaderStage Shader pipeline stage
+		 * @param[in] shaderSource Source of shader
+		 * @param[in] compiled Shader compilation event
+		 * @param[in] includePath Include path for shaders
+		 * @return Result if the compilation succeeds
+		 */
+		bool compileSource(ShaderStage shaderStage,
+						   const std::string& shaderSource,
+						   const ShaderCompiledFunction& compiled,
+						   const std::filesystem::path& includePath = "") override;
+		
+	};
+	
+	/** @} */
+	
+}
diff --git a/modules/shader_compiler/src/vkcv/shader/LLVMCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/LLVMCompiler.cpp
new file mode 100644
index 00000000..04435ae6
--- /dev/null
+++ b/modules/shader_compiler/src/vkcv/shader/LLVMCompiler.cpp
@@ -0,0 +1,119 @@
+
+#include "vkcv/shader/LLVMCompiler.hpp"
+
+#include <vkcv/File.hpp>
+#include <vkcv/Logger.hpp>
+
+#include <shady/driver.h>
+
+namespace vkcv::shader {
+
+    LLVMCompiler::LLVMCompiler(LLVMCompileTarget target)
+    : ShadyCompiler(), m_target(target) {}
+
+    static bool shadyCompileModule(Module* module,
+								   ShaderStage shaderStage,
+								   const std::string& shaderSource,
+								   const ShaderCompiledFunction &compiled,
+								   const std::filesystem::path &includePath) {
+		ShadyErrorCodes codes = driver_load_source_file(
+            SrcLLVM,
+            shaderSource.length(),
+			shaderSource.c_str(),
+            module
+		);
+
+		switch (codes) {
+			case NoError:
+				break;
+			case MissingInputArg:
+			case MissingOutputArg:
+			case InputFileDoesNotExist:
+			case InputFileIOError:
+			case MissingDumpCfgArg:
+			case MissingDumpIrArg:
+			case IncorrectLogLevel:
+			case InvalidTarget:
+			case ClangInvocationFailed:
+			default:
+				vkcv_log(LogLevel::ERROR, "Unknown error while loading shader");
+				return false;
+		}
+
+		const std::filesystem::path tmp_path = generateTemporaryFilePath();
+
+		DriverConfig config = default_driver_config();
+
+        config.target = TgtSPV;
+		config.output_filename = tmp_path.c_str();
+
+		codes = driver_compile(&config, module);
+		destroy_driver_config(&config);
+
+		switch (codes) {
+			case NoError:
+				break;
+			case MissingInputArg:
+			case MissingOutputArg:
+			case InputFileDoesNotExist:
+			case InputFileIOError:
+			case MissingDumpCfgArg:
+			case MissingDumpIrArg:
+			case IncorrectLogLevel:
+			case InvalidTarget:
+			case ClangInvocationFailed:
+			default:
+				vkcv_log(LogLevel::ERROR, "Unknown error while compiling shader");
+				return false;
+		}
+
+		if (compiled) {
+			compiled(shaderStage, tmp_path);
+		}
+
+		std::filesystem::remove(tmp_path);
+		return true;
+	}
+
+    static bool shadyCompileArena(IrArena* arena,
+								  ShaderStage shaderStage,
+								  const std::string& shaderSource,
+								  const ShaderCompiledFunction &compiled,
+								  const std::filesystem::path &includePath) {
+		Module* module = new_module(arena, "slim_module");
+
+		if (nullptr == module) {
+			vkcv_log(LogLevel::ERROR, "Module could not be created");
+			return false;
+		}
+
+		bool result = shadyCompileModule(module, shaderStage, shaderSource, compiled, includePath);
+
+		destroy_module(module);
+		return result;
+	}
+
+    bool LLVMCompiler::compileSource(ShaderStage shaderStage,
+                                     const std::string& shaderSource,
+						             const ShaderCompiledFunction& compiled,
+						             const std::filesystem::path& includePath) {
+        if (ShaderStage::COMPUTE != shaderStage) {
+			vkcv_log(LogLevel::ERROR, "Shader stage not supported");
+			return false;
+		}
+
+        ArenaConfig config = default_arena_config();
+		IrArena* arena = new_ir_arena(config);
+
+		if (nullptr == arena) {
+			vkcv_log(LogLevel::ERROR, "IR Arena could not be created");
+			return false;
+		}
+
+		bool result = shadyCompileArena(arena, shaderStage, shaderSource, compiled, includePath);
+
+		destroy_ir_arena(arena);
+        return result;
+    }
+
+}
diff --git a/modules/shader_compiler/src/vkcv/shader/ShadyCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/ShadyCompiler.cpp
index 54a10bf4..13319e22 100644
--- a/modules/shader_compiler/src/vkcv/shader/ShadyCompiler.cpp
+++ b/modules/shader_compiler/src/vkcv/shader/ShadyCompiler.cpp
@@ -8,127 +8,31 @@
 
 namespace vkcv::shader {
 	
-	ShadyCompiler::ShadyCompiler() : Compiler() {
-		// TODO
-	}
-	
-	ShadyCompiler::ShadyCompiler(const ShadyCompiler &other) : Compiler(other) {
-		// TODO
-	}
-	
-	ShadyCompiler::~ShadyCompiler() {
-		// TODO
-	}
-	
-	ShadyCompiler &ShadyCompiler::operator=(const ShadyCompiler &other) {
-		// TODO
-		return *this;
-	}
-
-	static bool shadyCompileModule(Module* module,
-								   ShaderStage shaderStage,
-								   const std::filesystem::path &shaderPath,
-								   const ShaderCompiledFunction &compiled,
-								   const std::filesystem::path &includePath) {
-		ShadyErrorCodes codes = driver_load_source_file_from_filename(
-			shaderPath.c_str(), module
-		);
-
-		switch (codes) {
-			case NoError:
-				break;
-			case MissingInputArg:
-			case MissingOutputArg:
-			case InputFileDoesNotExist:
-			case InputFileIOError:
-			case MissingDumpCfgArg:
-			case MissingDumpIrArg:
-			case IncorrectLogLevel:
-			case InvalidTarget:
-			case ClangInvocationFailed:
-			default:
-				vkcv_log(LogLevel::ERROR, "Unknown error while loading shader");
-				return false;
-		}
-
-		const std::filesystem::path tmp_path = generateTemporaryFilePath();
-
-		DriverConfig config = default_driver_config();
-
-		config.output_filename = tmp_path.c_str();
-
-		// TODO
-
-		codes = driver_compile(&config, module);
-		destroy_driver_config(&config);
-
-		switch (codes) {
-			case NoError:
-				break;
-			case MissingInputArg:
-			case MissingOutputArg:
-			case InputFileDoesNotExist:
-			case InputFileIOError:
-			case MissingDumpCfgArg:
-			case MissingDumpIrArg:
-			case IncorrectLogLevel:
-			case InvalidTarget:
-			case ClangInvocationFailed:
-			default:
-				vkcv_log(LogLevel::ERROR, "Unknown error while compiling shader");
-				return false;
-		}
-
-		if (compiled) {
-			compiled(shaderStage, tmp_path);
-		}
-
-		std::filesystem::remove(tmp_path);
-		return true;
-	}
-
-	static bool shadyCompileArena(IrArena* arena,
-								  ShaderStage shaderStage,
-								  const std::filesystem::path &shaderPath,
-								  const ShaderCompiledFunction &compiled,
-								  const std::filesystem::path &includePath) {
-		Module* module = new_module(arena, "main");
-
-		if (nullptr == module) {
-			vkcv_log(LogLevel::ERROR, "Module could not be created");
-			return false;
-		}
-
-		bool result = shadyCompileModule(module, shaderStage, shaderPath, compiled, includePath);
-
-		destroy_module(module);
-		return result;
-	}
+	ShadyCompiler::ShadyCompiler()
+	: Compiler() {}
 	
 	void ShadyCompiler::compile(ShaderStage shaderStage,
 								const std::filesystem::path &shaderPath,
 								const ShaderCompiledFunction &compiled,
 								const std::filesystem::path &includePath,
 								bool update) {
-		ArenaConfig config {};
-
-		// TODO
-
-		IrArena* arena = new_ir_arena(config);
-
-		if (nullptr == arena) {
-			vkcv_log(LogLevel::ERROR, "IR Arena could not be created");
-			return;
+		std::string shaderCode;
+		bool result = readTextFromFile(shaderPath, shaderCode);
+		
+		if (!result) {
+			vkcv_log(LogLevel::ERROR, "Loading shader failed: (%s)", shaderPath.string().c_str());
 		}
-
-		bool result = shadyCompileArena(arena, shaderStage, shaderPath, compiled, includePath);
-
-		destroy_ir_arena(arena);
-
+		
+		if (!includePath.empty()) {
+			result = compileSource(shaderStage, shaderCode, compiled, includePath);
+		} else {
+			result = compileSource(shaderStage, shaderCode, compiled, shaderPath.parent_path());
+		}
+		
 		if (!result) {
 			vkcv_log(LogLevel::ERROR, "Shader compilation failed: (%s)", shaderPath.string().c_str());
 		}
-
+		
 		if (update) {
 			// TODO: Shader hot compilation during runtime
 		}
diff --git a/modules/shader_compiler/src/vkcv/shader/SlimCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/SlimCompiler.cpp
new file mode 100644
index 00000000..940ae700
--- /dev/null
+++ b/modules/shader_compiler/src/vkcv/shader/SlimCompiler.cpp
@@ -0,0 +1,119 @@
+
+#include "vkcv/shader/SlimCompiler.hpp"
+
+#include <vkcv/File.hpp>
+#include <vkcv/Logger.hpp>
+
+#include <shady/driver.h>
+
+namespace vkcv::shader {
+
+    SlimCompiler::SlimCompiler(SlimCompileTarget target)
+    : ShadyCompiler(), m_target(target) {}
+
+    static bool shadyCompileModule(Module* module,
+								   ShaderStage shaderStage,
+								   const std::string& shaderSource,
+								   const ShaderCompiledFunction &compiled,
+								   const std::filesystem::path &includePath) {
+		ShadyErrorCodes codes = driver_load_source_file(
+            SrcSlim,
+            shaderSource.length(),
+			shaderSource.c_str(),
+            module
+		);
+
+		switch (codes) {
+			case NoError:
+				break;
+			case MissingInputArg:
+			case MissingOutputArg:
+			case InputFileDoesNotExist:
+			case InputFileIOError:
+			case MissingDumpCfgArg:
+			case MissingDumpIrArg:
+			case IncorrectLogLevel:
+			case InvalidTarget:
+			case ClangInvocationFailed:
+			default:
+				vkcv_log(LogLevel::ERROR, "Unknown error while loading shader");
+				return false;
+		}
+
+		const std::filesystem::path tmp_path = generateTemporaryFilePath();
+
+		DriverConfig config = default_driver_config();
+
+        config.target = TgtSPV;
+		config.output_filename = tmp_path.c_str();
+
+		codes = driver_compile(&config, module);
+		destroy_driver_config(&config);
+
+		switch (codes) {
+			case NoError:
+				break;
+			case MissingInputArg:
+			case MissingOutputArg:
+			case InputFileDoesNotExist:
+			case InputFileIOError:
+			case MissingDumpCfgArg:
+			case MissingDumpIrArg:
+			case IncorrectLogLevel:
+			case InvalidTarget:
+			case ClangInvocationFailed:
+			default:
+				vkcv_log(LogLevel::ERROR, "Unknown error while compiling shader");
+				return false;
+		}
+
+		if (compiled) {
+			compiled(shaderStage, tmp_path);
+		}
+
+		std::filesystem::remove(tmp_path);
+		return true;
+	}
+
+    static bool shadyCompileArena(IrArena* arena,
+								  ShaderStage shaderStage,
+								  const std::string& shaderSource,
+								  const ShaderCompiledFunction &compiled,
+								  const std::filesystem::path &includePath) {
+		Module* module = new_module(arena, "slim_module");
+
+		if (nullptr == module) {
+			vkcv_log(LogLevel::ERROR, "Module could not be created");
+			return false;
+		}
+
+		bool result = shadyCompileModule(module, shaderStage, shaderSource, compiled, includePath);
+
+		destroy_module(module);
+		return result;
+	}
+
+    bool SlimCompiler::compileSource(ShaderStage shaderStage,
+                                     const std::string& shaderSource,
+						             const ShaderCompiledFunction& compiled,
+						             const std::filesystem::path& includePath) {
+        if (ShaderStage::COMPUTE != shaderStage) {
+			vkcv_log(LogLevel::ERROR, "Shader stage not supported");
+			return false;
+		}
+
+        ArenaConfig config = default_arena_config();
+		IrArena* arena = new_ir_arena(config);
+
+		if (nullptr == arena) {
+			vkcv_log(LogLevel::ERROR, "IR Arena could not be created");
+			return false;
+		}
+
+		bool result = shadyCompileArena(arena, shaderStage, shaderSource, compiled, includePath);
+
+		destroy_ir_arena(arena);
+        return result;
+    }
+
+}
-- 
GitLab