Skip to content

Commit

Permalink
merian: Add glslangValidator and glslc compilers, automatically add d…
Browse files Browse the repository at this point in the history
…efines and includes for the Merian framework
  • Loading branch information
LDAP committed Nov 6, 2024
1 parent 91038ea commit c2b62d1
Show file tree
Hide file tree
Showing 20 changed files with 540 additions and 65 deletions.
39 changes: 39 additions & 0 deletions include/merian/utils/filesystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include <string>
#include <unistd.h>

#ifdef _WIN32
#include <cstdio>
#endif

namespace merian {

inline std::string temporary_file() {
#ifdef _WIN32
return std::tmpnam(nullptr);
#else
// std::tmpnam is deprecated
const char* tem_dir_name = std::getenv("TMPDIR");
std::string tmp_file_name_template = (tem_dir_name != nullptr) ? tem_dir_name : "";
#ifdef P_tmpdir
if (tmp_file_name_template.empty()) {
tmp_file_name_template = P_tmpdir;
}
#endif
if (tmp_file_name_template.empty()) {
tmp_file_name_template = "/tmp";
}

tmp_file_name_template += "/merianXXXXXX";
const int fd = mkstemp(const_cast<char*>(tmp_file_name_template.c_str()));
if (fd > 0) {
// immediately close again...
close(fd);
}

return tmp_file_name_template;
#endif
}

} // namespace merian
13 changes: 11 additions & 2 deletions include/merian/vk/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "merian/io/file_loader.hpp"
#include "merian/utils/concurrent/thread_pool.hpp"
#include <map>
#include <ranges>
#include <spdlog/logger.h>

#include <typeindex>
Expand Down Expand Up @@ -125,6 +127,7 @@ class Context : public std::enable_shared_from_this<Context> {
std::string filter_device_name);
void find_queues();
void create_device_and_queues(uint32_t preffered_number_compute_queues);
void prepare_shader_include_defines();

private: // Helper
void extensions_check_instance_layer_support();
Expand Down Expand Up @@ -179,12 +182,14 @@ class Context : public std::enable_shared_from_this<Context> {

bool instance_extension_enabled(const std::string& name) const;

auto get_context_extensions() const;

const std::vector<const char*>& get_enabled_device_extensions() const;

const std::vector<const char*>& get_enabled_instance_extensions() const;

const std::vector<std::string>& get_default_shader_include_paths() const;

const std::map<std::string, std::string>& get_default_shader_macro_definitions() const;

private:
std::unordered_map<std::type_index, std::shared_ptr<Extension>> extensions;

Expand Down Expand Up @@ -257,6 +262,10 @@ class Context : public std::enable_shared_from_this<Context> {
std::weak_ptr<CommandPool> cmd_pool_T;
// Convenience command pool for compute (can be nullptr in very rare occasions)
std::weak_ptr<CommandPool> cmd_pool_C;


std::vector<std::string> default_shader_include_paths;
std::map<std::string, std::string> default_shader_macro_definitions;
};

} // namespace merian
Expand Down
12 changes: 11 additions & 1 deletion include/merian/vk/extension/extension.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "merian/vk/context.hpp"
#include <spdlog/spdlog.h>
#include <vector>
#include <map>

namespace merian {

Expand All @@ -21,7 +22,7 @@ class Extension {
friend Context;

public:
Extension(std::string name) : name(name) {}
Extension(const std::string& name) : name(name) {}

virtual ~Extension() = 0;

Expand Down Expand Up @@ -109,6 +110,15 @@ class Extension {
spdlog::warn("extension {} not supported ({})", name, reason);
}

// OTHER

// return strings that should be defined when compiling shaders with Merians shader compiler.
// Note that device and instance extensions are automatically defined as
// MERIAN_DEVICE_EXT_ENABLE_<NAME> and MERIAN_INSTANCE_EXT_ENABLE_<NAME>
virtual std::map<std::string, std::string> shader_macro_definitions() {
return {};
}

public:
const std::string name;
};
Expand Down
105 changes: 82 additions & 23 deletions include/merian/vk/shader/shader_compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,87 @@

namespace merian {

// A compiler for shaders.
//
// Include paths for the merian-nodes library and context extensions must be automatically added.
class ShaderCompiler;
using ShaderCompilerHandle = std::shared_ptr<ShaderCompiler>;

class ShaderCompiler {
public:
class compilation_failed : public std::runtime_error {
public:
compilation_failed(const std::string& what) : std::runtime_error(what) {}
};

inline static const std::map<std::string, vk::ShaderStageFlagBits> EXTENSION_SHADER_STAGE_MAP =
{
{".vert", vk::ShaderStageFlagBits::eVertex},
{".tesc", vk::ShaderStageFlagBits::eTessellationControl},
{".tese", vk::ShaderStageFlagBits::eTessellationEvaluation},
{".geom", vk::ShaderStageFlagBits::eGeometry},
{".frag", vk::ShaderStageFlagBits::eFragment},
{".comp", vk::ShaderStageFlagBits::eCompute},
{".mesh", vk::ShaderStageFlagBits::eMeshEXT},
{".task", vk::ShaderStageFlagBits::eTaskEXT},
{".rgen", vk::ShaderStageFlagBits::eRaygenKHR},
{".rint", vk::ShaderStageFlagBits::eIntersectionKHR},
{".rahit", vk::ShaderStageFlagBits::eAnyHitKHR},
{".rchit", vk::ShaderStageFlagBits::eClosestHitKHR},
{".rmiss", vk::ShaderStageFlagBits::eMissKHR},
{".rcall", vk::ShaderStageFlagBits::eCallableKHR},
};

inline static const std::map<vk::ShaderStageFlagBits, std::string> SHADER_STAGE_EXTENSION_MAP =
{
{vk::ShaderStageFlagBits::eVertex, ".vert"},
{vk::ShaderStageFlagBits::eTessellationControl, ".tesc"},
{vk::ShaderStageFlagBits::eTessellationEvaluation, ".tese"},
{vk::ShaderStageFlagBits::eGeometry, ".geom"},
{vk::ShaderStageFlagBits::eFragment, ".frag"},
{vk::ShaderStageFlagBits::eCompute, ".comp"},
{vk::ShaderStageFlagBits::eMeshEXT, ".mesh"},
{vk::ShaderStageFlagBits::eTaskEXT, ".task"},
{vk::ShaderStageFlagBits::eRaygenKHR, ".rgen"},
{vk::ShaderStageFlagBits::eIntersectionKHR, ".rint"},
{vk::ShaderStageFlagBits::eAnyHitKHR, ".rahit"},
{vk::ShaderStageFlagBits::eClosestHitKHR, ".rchit"},
{vk::ShaderStageFlagBits::eMissKHR, ".rmiss"},
{vk::ShaderStageFlagBits::eCallableKHR, ".rcall"},
};

public:
ShaderCompiler() {}
// Returns any of the available shader compilers. Returns nullptr if none is available.
static ShaderCompilerHandle
get(const ContextHandle& context,
const std::vector<std::string>& user_include_paths = {},
const std::map<std::string, std::string>& user_macro_definitions = {});

ShaderCompiler(const ContextHandle& context,
const std::vector<std::string>& user_include_paths = {},
const std::map<std::string, std::string>& user_macro_definitions = {});

virtual ~ShaderCompiler() = 0;

// ------------------------------------------------

// Attempt to guess the shader_kind from the file extension if shader_kind = std::nullopt.
//
// May throw compilation_failed.
std::vector<uint32_t>
virtual std::vector<uint32_t>
compile_glsl(const std::filesystem::path& path,
const std::optional<vk::ShaderStageFlagBits> optional_shader_kind = std::nullopt) {
return compile_glsl(FileLoader::load_file(path), path.string(),
optional_shader_kind.value_or(guess_kind(path)));
}

// May throw compilation_failed.
virtual std::vector<uint32_t> compile_glsl(const std::string& source,
const std::string& source_name,
const vk::ShaderStageFlagBits shader_kind) = 0;

// ------------------------------------------------

ShaderModuleHandle compile_glsl_to_shadermodule(
const ContextHandle& context,
const std::filesystem::path& path,
Expand All @@ -50,13 +109,20 @@ class ShaderCompiler {
context, compile_glsl(source, source_name, shader_kind), shader_kind);
}

// May throw compilation_failed.
virtual std::vector<uint32_t> compile_glsl(const std::string& source,
const std::string& source_name,
const vk::ShaderStageFlagBits shader_kind) = 0;
// ------------------------------------------------

const std::vector<std::string>& get_include_paths() const {
return include_paths;
}

const std::map<std::string, std::string>& get_macro_definitions() const {
return macro_definitions;
}

virtual bool available() const = 0;

private:
vk::ShaderStageFlagBits guess_kind(const std::filesystem::path& path) {
static vk::ShaderStageFlagBits guess_kind(const std::filesystem::path& path) {
std::string extension;
if (path.extension().string() == ".glsl") {
extension = std::filesystem::path(path.string().substr(0, path.string().size() - 5))
Expand All @@ -65,24 +131,17 @@ class ShaderCompiler {
} else {
extension = path.extension().string();
}
if (extension == ".vert") {
return vk::ShaderStageFlagBits::eVertex;
} else if (extension == ".tesc") {
return vk::ShaderStageFlagBits::eTessellationControl;
} else if (extension == ".tese") {
return vk::ShaderStageFlagBits::eTessellationEvaluation;
} else if (extension == ".geom") {
return vk::ShaderStageFlagBits::eGeometry;
} else if (extension == ".frag") {
return vk::ShaderStageFlagBits::eFragment;
} else if (extension == ".comp") {
return vk::ShaderStageFlagBits::eCompute;
} else {
throw compilation_failed{
fmt::format("Shader kind could not be determined for path {}", path.string())};

if (EXTENSION_SHADER_STAGE_MAP.contains(extension)) {
return EXTENSION_SHADER_STAGE_MAP.at(extension);
}

throw compilation_failed{
fmt::format("Shader kind could not be determined for path {}", path.string())};
}

std::vector<std::string> include_paths;
std::map<std::string, std::string> macro_definitions;
};
using ShaderCompilerHandle = std::shared_ptr<ShaderCompiler>;

} // namespace merian
16 changes: 7 additions & 9 deletions include/merian/vk/shader/shader_compiler_shaderc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,16 @@
#include "merian/vk/shader/shader_compiler.hpp"
#include <map>

#ifdef __has_include
#if !__has_include(<shaderc/shaderc.hpp>)
static_assert(false, "shaderc is required for ShadercCompiler");
#else
#include <shaderc/shaderc.hpp>
#endif
#else
#ifdef MERIAN_SHADERC_FOUND
#include <shaderc/shaderc.hpp>
#endif

namespace merian {

class ShadercCompiler : public ShaderCompiler {
public:
// Include paths for the merian-nodes library are automatically added
ShadercCompiler(const std::vector<std::string>& include_paths = {},
ShadercCompiler(const ContextHandle& context,
const std::vector<std::string>& include_paths = {},
const std::map<std::string, std::string>& macro_definitions = {});

~ShadercCompiler();
Expand All @@ -27,9 +21,13 @@ class ShadercCompiler : public ShaderCompiler {
const std::string& source_name,
const vk::ShaderStageFlagBits shader_kind) override;

bool available() const override;

private:
#ifdef MERIAN_SHADERC_FOUND
shaderc::Compiler shader_compiler;
shaderc::CompileOptions compile_options;
#endif
};

} // namespace merian
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include "merian/vk/shader/shader_compiler.hpp"
#include <map>

namespace merian {

// Uses glslangValidator executable to compile shaders.
class SystemGlslangValidatorCompiler : public ShaderCompiler {
public:
// Include paths for the merian-nodes library are automatically added
SystemGlslangValidatorCompiler(
const ContextHandle& context,
const std::vector<std::string>& include_paths = {},
const std::map<std::string, std::string>& macro_definitions = {});

~SystemGlslangValidatorCompiler();

std::vector<uint32_t> compile_glsl(const std::string& source,
const std::string& source_name,
const vk::ShaderStageFlagBits shader_kind) override;

bool available() const override;

private:
const ContextHandle context;
};

} // namespace merian
28 changes: 28 additions & 0 deletions include/merian/vk/shader/shader_compiler_system_glslc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include "merian/vk/shader/shader_compiler.hpp"
#include <map>

namespace merian {

// Uses shaderc executable to compile shaders.
class SystemGlslcCompiler : public ShaderCompiler {
public:
// Include paths for the merian-nodes library are automatically added
SystemGlslcCompiler(const ContextHandle& context,
const std::vector<std::string>& include_paths = {},
const std::map<std::string, std::string>& macro_definitions = {});

~SystemGlslcCompiler();

std::vector<uint32_t> compile_glsl(const std::string& source,
const std::string& source_name,
const vk::ShaderStageFlagBits shader_kind) override;

bool available() const override;

private:
const ContextHandle context;
};

} // namespace merian
2 changes: 1 addition & 1 deletion include/merian/vk/shader/shader_module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ShaderModule : public std::enable_shared_from_this<ShaderModule> {
ShaderModule() = delete;

ShaderModule(const ContextHandle& context,
const std::string spv_filename,
const std::string& spv_filename,
const vk::ShaderStageFlagBits stage_flags = vk::ShaderStageFlagBits::eCompute,
const std::optional<FileLoader>& file_loader = std::nullopt);

Expand Down
Loading

0 comments on commit c2b62d1

Please sign in to comment.