diff --git a/cmake/BuildShaders.cmake b/cmake/BuildShaders.cmake index 0445552..9525850 100755 --- a/cmake/BuildShaders.cmake +++ b/cmake/BuildShaders.cmake @@ -1,9 +1,9 @@ macro(compile_shader src) string(REGEX REPLACE "\\.[^.]*$" "" MYFILE_WITHOUT_EXT ${src}) - set(SHADER_COMPILER_COMMAND $) + set(SHADER_COMPILER_COMMAND $) if(ENABLE_IOS) - set(SHADER_COMPILER_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../build/bin/Debug/ShaderCompiler") + set(SHADER_COMPILER_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/../build/bin/Debug/ShaderCompilerTool") endif() set(EXTRA_PLATFORM_ARG "0") @@ -36,7 +36,7 @@ function(add_shader) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/shaders) - add_custom_target(BuildShaders DEPENDS ${SPV_FILES} ShaderCompiler) + add_custom_target(BuildShaders DEPENDS ${SPV_FILES} ShaderCompilerTool) add_dependencies(${add_shader_TARGET} BuildShaders) set(ALL_SHADER_FILES ${SPV_FILES} CACHE INTERNAL "" FORCE) diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 57f5875..31171a5 100755 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(gfx) add_subdirectory(math) add_subdirectory(log) add_subdirectory(asset) +add_subdirectory(shadercompiler) if(NOT ENABLE_IOS AND NOT ENABLE_TVOS) add_subdirectory(audio) diff --git a/engine/renderer/CMakeLists.txt b/engine/renderer/CMakeLists.txt index b147780..914f9ee 100755 --- a/engine/renderer/CMakeLists.txt +++ b/engine/renderer/CMakeLists.txt @@ -7,8 +7,7 @@ set(SRC include/imguipass.hpp include/smaapass.hpp include/scenecapture.hpp - include/shadercompiler.hpp - include/DirStackIncluder.h + include/materialcompiler.hpp include/dofpass.hpp src/renderer.cpp @@ -17,7 +16,7 @@ set(SRC src/imguipass.cpp src/smaapass.cpp src/scenecapture.cpp - src/shadercompiler.cpp + src/materialcompiler.cpp src/dofpass.cpp) add_library(Renderer STATIC ${SRC}) @@ -32,11 +31,9 @@ target_link_libraries(Renderer Core imgui SMAA::SMAA - ${CROSS_LIBS}) + ShaderCompiler) target_include_directories(Renderer PUBLIC include) -set_target_properties(Renderer PROPERTIES CXX_STANDARD 17) -target_compile_features(Renderer PUBLIC cxx_std_17) -set_target_properties(Renderer PROPERTIES CXX_EXTENSIONS OFF) +set_engine_properties(Renderer) include(../../cmake/BuildShaders.cmake) diff --git a/engine/renderer/include/shadercompiler.hpp b/engine/renderer/include/materialcompiler.hpp similarity index 93% rename from engine/renderer/include/shadercompiler.hpp rename to engine/renderer/include/materialcompiler.hpp index 79a5a5c..79e11fa 100755 --- a/engine/renderer/include/shadercompiler.hpp +++ b/engine/renderer/include/materialcompiler.hpp @@ -13,7 +13,7 @@ constexpr int tangent_buffer_index = 5; constexpr int bitangent_buffer_index = 6; constexpr int bone_buffer_index = 7; -class ShaderCompiler { +class MaterialCompiler { public: GFXPipeline* create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only = false, bool cubemap = false); GFXPipeline* create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only = false); @@ -24,4 +24,4 @@ public: std::variant> compile_material_fragment(Material& material, bool use_ibl = true); }; -static ShaderCompiler shader_compiler; +static MaterialCompiler material_compiler; diff --git a/engine/renderer/src/shadercompiler.cpp b/engine/renderer/src/materialcompiler.cpp similarity index 65% rename from engine/renderer/src/shadercompiler.cpp rename to engine/renderer/src/materialcompiler.cpp index 953027a..a791c3a 100755 --- a/engine/renderer/src/shadercompiler.cpp +++ b/engine/renderer/src/materialcompiler.cpp @@ -1,181 +1,10 @@ -#include "shadercompiler.hpp" - -#include -#include -#include +#include "materialcompiler.hpp" #include "file.hpp" #include "log.hpp" #include "engine.hpp" #include "string_utils.hpp" -#include "DirStackIncluder.h" - -const TBuiltInResource DefaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 4096, - /* .MaxVaryingFloats = */ 64, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 4096, - /* .MaxDrawBuffers = */ 32, - /* .MaxVertexUniformVectors = */ 128, - /* .MaxVaryingVectors = */ 8, - /* .MaxFragmentUniformVectors = */ 16, - /* .MaxVertexOutputVectors = */ 16, - /* .MaxFragmentInputVectors = */ 15, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 16, - /* .MaxComputeImageUniforms = */ 8, - /* .MaxComputeAtomicCounters = */ 8, - /* .MaxComputeAtomicCounterBuffers = */ 1, - /* .MaxVaryingComponents = */ 60, - /* .MaxVertexOutputComponents = */ 64, - /* .MaxGeometryInputComponents = */ 64, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 8, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, - /* .MaxCombinedShaderOutputResources = */ 8, - /* .MaxImageSamples = */ 0, - /* .MaxVertexImageUniforms = */ 0, - /* .MaxTessControlImageUniforms = */ 0, - /* .MaxTessEvaluationImageUniforms = */ 0, - /* .MaxGeometryImageUniforms = */ 0, - /* .MaxFragmentImageUniforms = */ 8, - /* .MaxCombinedImageUniforms = */ 8, - /* .MaxGeometryTextureImageUnits = */ 16, - /* .MaxGeometryOutputVertices = */ 256, - /* .MaxGeometryTotalOutputComponents = */ 1024, - /* .MaxGeometryUniformComponents = */ 1024, - /* .MaxGeometryVaryingComponents = */ 64, - /* .MaxTessControlInputComponents = */ 128, - /* .MaxTessControlOutputComponents = */ 128, - /* .MaxTessControlTextureImageUnits = */ 16, - /* .MaxTessControlUniformComponents = */ 1024, - /* .MaxTessControlTotalOutputComponents = */ 4096, - /* .MaxTessEvaluationInputComponents = */ 128, - /* .MaxTessEvaluationOutputComponents = */ 128, - /* .MaxTessEvaluationTextureImageUnits = */ 16, - /* .MaxTessEvaluationUniformComponents = */ 1024, - /* .MaxTessPatchComponents = */ 120, - /* .MaxPatchVertices = */ 32, - /* .MaxTessGenLevel = */ 64, - /* .MaxViewports = */ 16, - /* .MaxVertexAtomicCounters = */ 0, - /* .MaxTessControlAtomicCounters = */ 0, - /* .MaxTessEvaluationAtomicCounters = */ 0, - /* .MaxGeometryAtomicCounters = */ 0, - /* .MaxFragmentAtomicCounters = */ 8, - /* .MaxCombinedAtomicCounters = */ 8, - /* .MaxAtomicCounterBindings = */ 1, - /* .MaxVertexAtomicCounterBuffers = */ 0, - /* .MaxTessControlAtomicCounterBuffers = */ 0, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, - /* .MaxGeometryAtomicCounterBuffers = */ 0, - /* .MaxFragmentAtomicCounterBuffers = */ 1, - /* .MaxCombinedAtomicCounterBuffers = */ 1, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 4, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - /* .maxDualSourceDrawBuffersEXT = */ 4, - - /* .limits = */ TLimits{ - /* .nonInductiveForLoops = */ true, - /* .whileLoops = */ true, - /* .doWhileLoops = */ true, - /* .generalUniformIndexing = */ true, - /* .generalAttributeMatrixVectorIndexing = */ true, - /* .generalVaryingIndexing = */ true, - /* .generalSamplerIndexing = */ true, - /* .generalVariableIndexing = */ true, - /* .generalConstantMatrixVectorIndexing = */ true, - }}; - - -const std::vector CompileGLSL(const std::string& filename, EShLanguage ShaderType, bool skinned, bool cubemap) { - std::string newString = "#version 430 core\n"; - - newString += "#extension GL_GOOGLE_include_directive : enable\n"; - newString += "#extension GL_GOOGLE_cpp_style_line_directive : enable\n"; - - if(skinned) - newString += "#define BONE\n"; - - if(cubemap) - newString += "#define CUBEMAP\n"; - - newString += "#line 1\n"; - - newString += filename; - - const char* InputCString = newString.c_str(); - - glslang::TShader Shader(ShaderType); - - Shader.setStrings(&InputCString, 1); - - int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 - glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_1; - glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0; - - Shader.setEnvInput(glslang::EShSourceGlsl, ShaderType, glslang::EShClientVulkan, ClientInputSemanticsVersion); - Shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); - Shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion); - - TBuiltInResource Resources = DefaultTBuiltInResource; - EShMessages messages = (EShMessages) (EShMsgSpvRules); - - DirStackFileIncluder includer; - includer.pushExternalLocalDirectory(file::get_domain_path(file::Domain::Internal).string()); - - if (!Shader.parse(&Resources, 100, false, (EShMessages)0, includer)) { - console::error(System::Renderer, "{}", Shader.getInfoLog()); - - return {}; - } - - glslang::TProgram Program; - Program.addShader(&Shader); - - if(!Program.link(messages)) { - console::error(System::None, "Failed to link shader: {} {} {}", filename, Shader.getInfoLog(), Shader.getInfoDebugLog()); - - return {}; - } - - std::vector SpirV; - spv::SpvBuildLogger logger; - glslang::SpvOptions spvOptions; - glslang::GlslangToSpv(*Program.getIntermediate(ShaderType), SpirV, &logger, &spvOptions); - - return SpirV; -} +#include "shadercompiler.hpp" std::variant> get_shader(std::string filename, bool skinned, bool cubemap) { auto shader_file = file::open(file::internal_domain / filename); @@ -184,31 +13,24 @@ std::variant> get_shader(std::string filename return ""; } - EShLanguage lang; + ShaderStage stage; if(filename.find("vert") != std::string::npos) { - lang = EShLangVertex; + stage = ShaderStage::Vertex; } else { - lang = EShLangFragment; + stage = ShaderStage::Fragment; } - auto vertexSPIRV = CompileGLSL(shader_file->read_as_string(), lang, skinned, cubemap); + CompileOptions options; + if(skinned) + options.add_definition("BONE"); -#ifdef PLATFORM_MACOS - spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); - - spirv_cross::CompilerMSL::Options opts; - opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; - opts.enable_decoration_binding = true; - - msl.set_msl_options(opts); - - return msl.compile(); -#else - return vertexSPIRV; -#endif + if(cubemap) + options.add_definition("CUBEMAP"); + + return shader_compiler.compile(ShaderLanguage::GLSL, stage, shader_file->read_as_string(), ShaderLanguage::MSL, options)->source; } -GFXPipeline* ShaderCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) { +GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) { // take vertex src std::string vertex_path = createInfo.shaders.vertex_path.data(); vertex_path += ".glsl"; @@ -245,7 +67,7 @@ GFXPipeline* ShaderCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInf return engine->get_gfx()->create_graphics_pipeline(createInfo); } -GFXPipeline* ShaderCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only) { +GFXPipeline* MaterialCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only) { createInfo.label += " (Skinned)"; // take vertex src @@ -290,9 +112,7 @@ GFXPipeline* ShaderCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateIn return engine->get_gfx()->create_graphics_pipeline(createInfo); } -std::tuple ShaderCompiler::create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only) { - glslang::InitializeProcess(); - +std::tuple MaterialCompiler::create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only) { auto st = create_static_pipeline(createInfo, positions_only); auto ss = create_skinned_pipeline(createInfo, positions_only); @@ -364,7 +184,7 @@ layout(push_constant, binding = 0) uniform PushConstant {\n \ int materialOffset;\n \ };\n"; -std::variant> ShaderCompiler::compile_material_fragment(Material& material, bool use_ibl) { +std::variant> MaterialCompiler::compile_material_fragment(Material& material, bool use_ibl) { walked_nodes.clear(); if(!render_options.enable_ibl) @@ -567,19 +387,5 @@ std::variant> ShaderCompiler::compile_materia src += "}\n"; - auto vertexSPIRV = CompileGLSL(src, EShLangFragment, false, false); - -#ifdef PLATFORM_MACOS - spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); - - spirv_cross::CompilerMSL::Options opts; - opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; - opts.enable_decoration_binding = true; - - msl.set_msl_options(opts); - - return msl.compile(); -#else - return vertexSPIRV; -#endif + return shader_compiler.compile(ShaderLanguage::GLSL, ShaderStage::Fragment, src, ShaderLanguage::MSL)->source; } diff --git a/engine/renderer/src/renderer.cpp b/engine/renderer/src/renderer.cpp index 268f701..cd30165 100755 --- a/engine/renderer/src/renderer.cpp +++ b/engine/renderer/src/renderer.cpp @@ -18,10 +18,11 @@ #include "shadowpass.hpp" #include "smaapass.hpp" #include "scenecapture.hpp" -#include "shadercompiler.hpp" +#include "materialcompiler.hpp" #include "assertions.hpp" #include "dofpass.hpp" #include "frustum.hpp" +#include "shadercompiler.hpp" struct ElementInstance { Vector4 color; @@ -83,6 +84,8 @@ struct UIPushConstant { Renderer::Renderer(GFX* gfx, const bool enable_imgui) : gfx(gfx) { Expects(gfx != nullptr); + shader_compiler.set_include_path(file::get_domain_path(file::Domain::Internal).string()); + createDummyTexture(); shadow_pass = std::make_unique(gfx); @@ -691,19 +694,19 @@ void Renderer::create_mesh_pipeline(Material& material) { pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha; pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha; - pipelineInfo.shaders.fragment_src = shader_compiler.compile_material_fragment(material); + pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material); pipelineInfo.shaders.fragment_path = ""; - auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo); + auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo); material.static_pipeline = static_pipeline; material.skinned_pipeline = skinned_pipeline; pipelineInfo.render_pass = scene_capture->renderPass; - pipelineInfo.shaders.fragment_src = shader_compiler.compile_material_fragment(material, false); // scene capture does not use IBL + pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material, false); // scene capture does not use IBL - material.capture_pipeline = shader_compiler.create_static_pipeline(pipelineInfo, false, true); + material.capture_pipeline = material_compiler.create_static_pipeline(pipelineInfo, false, true); } void Renderer::createDummyTexture() { diff --git a/engine/renderer/src/scenecapture.cpp b/engine/renderer/src/scenecapture.cpp index df4bd2d..b5ce59e 100755 --- a/engine/renderer/src/scenecapture.cpp +++ b/engine/renderer/src/scenecapture.cpp @@ -7,7 +7,7 @@ #include "engine.hpp" #include "renderer.hpp" #include "shadowpass.hpp" -#include "shadercompiler.hpp" +#include "materialcompiler.hpp" #include "frustum.hpp" struct PushConstant { diff --git a/engine/renderer/src/shadowpass.cpp b/engine/renderer/src/shadowpass.cpp index 749e762..3fb93b8 100755 --- a/engine/renderer/src/shadowpass.cpp +++ b/engine/renderer/src/shadowpass.cpp @@ -5,7 +5,7 @@ #include "gfx.hpp" #include "log.hpp" #include "engine.hpp" -#include "shadercompiler.hpp" +#include "materialcompiler.hpp" #include "assertions.hpp" #include "frustum.hpp" @@ -325,7 +325,7 @@ void ShadowPass::create_pipelines() { { pipelineInfo.label = "Sun Shadow"; - auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo, true); + auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo, true); static_sun_pipeline = static_pipeline; skinned_sun_pipeline = skinned_pipeline; @@ -337,7 +337,7 @@ void ShadowPass::create_pipelines() { pipelineInfo.render_pass = cube_render_pass; - auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo, true); + auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo, true); static_spot_pipeline = static_pipeline; skinned_spot_pipeline = skinned_pipeline; @@ -349,7 +349,7 @@ void ShadowPass::create_pipelines() { pipelineInfo.shaders.fragment_path = "omnishadow.frag"; - auto [static_pipeline, skinned_pipeline] = shader_compiler.create_pipeline_permutations(pipelineInfo, true); + auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo, true); static_point_pipeline = static_pipeline; skinned_point_pipeline = skinned_pipeline; diff --git a/engine/shadercompiler/CMakeLists.txt b/engine/shadercompiler/CMakeLists.txt new file mode 100755 index 0000000..e079267 --- /dev/null +++ b/engine/shadercompiler/CMakeLists.txt @@ -0,0 +1,15 @@ +set(SRC + include/shadercompiler.hpp + + src/shadercompiler.cpp + src/includer.hpp + src/defaultresources.hpp) + +add_library(ShaderCompiler STATIC ${SRC}) +target_link_libraries(ShaderCompiler + PRIVATE + Utility + Log + ${CROSS_LIBS}) +target_include_directories(ShaderCompiler PUBLIC include PRIVATE src) +set_engine_properties(ShaderCompiler) diff --git a/engine/shadercompiler/include/shadercompiler.hpp b/engine/shadercompiler/include/shadercompiler.hpp new file mode 100755 index 0000000..91f3255 --- /dev/null +++ b/engine/shadercompiler/include/shadercompiler.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include +#include + +enum class ShaderStage { + Vertex, + Fragment +}; + +enum class ShaderLanguage { + GLSL, + MSL, + SPIRV +}; + +class CompileOptions { +public: + void add_definition(const std::string_view name) { + definitions.emplace_back(name); + } + + std::vector definitions; + + bool is_apple_mobile = false; +}; + +class ShaderSource { +public: + ShaderSource(const std::string source_string) : source(source_string) {} + ShaderSource(const std::vector source_bytecode) : source(source_bytecode) {} + + std::variant> source; + + std::string_view as_string() const { + return std::get(source); + } + + std::vector as_bytecode() const { + return std::get>(source); + } +}; + +class ShaderCompiler { +public: + ShaderCompiler(); + + void set_include_path(const std::string_view path); + + /** + Compiles from one shader language to another shader language. + */ + std::optional compile(const ShaderLanguage from_language, const ShaderStage shader_stage, const ShaderSource& shader_source, const ShaderLanguage to_language, const CompileOptions& options = CompileOptions()); +}; + +static inline ShaderCompiler shader_compiler; diff --git a/engine/shadercompiler/src/defaultresources.hpp b/engine/shadercompiler/src/defaultresources.hpp new file mode 100755 index 0000000..74aa340 --- /dev/null +++ b/engine/shadercompiler/src/defaultresources.hpp @@ -0,0 +1,108 @@ +#pragma once + +const TBuiltInResource DefaultTBuiltInResource = { + /* .MaxLights = */ 32, + /* .MaxClipPlanes = */ 6, + /* .MaxTextureUnits = */ 32, + /* .MaxTextureCoords = */ 32, + /* .MaxVertexAttribs = */ 64, + /* .MaxVertexUniformComponents = */ 4096, + /* .MaxVaryingFloats = */ 64, + /* .MaxVertexTextureImageUnits = */ 32, + /* .MaxCombinedTextureImageUnits = */ 80, + /* .MaxTextureImageUnits = */ 32, + /* .MaxFragmentUniformComponents = */ 4096, + /* .MaxDrawBuffers = */ 32, + /* .MaxVertexUniformVectors = */ 128, + /* .MaxVaryingVectors = */ 8, + /* .MaxFragmentUniformVectors = */ 16, + /* .MaxVertexOutputVectors = */ 16, + /* .MaxFragmentInputVectors = */ 15, + /* .MinProgramTexelOffset = */ -8, + /* .MaxProgramTexelOffset = */ 7, + /* .MaxClipDistances = */ 8, + /* .MaxComputeWorkGroupCountX = */ 65535, + /* .MaxComputeWorkGroupCountY = */ 65535, + /* .MaxComputeWorkGroupCountZ = */ 65535, + /* .MaxComputeWorkGroupSizeX = */ 1024, + /* .MaxComputeWorkGroupSizeY = */ 1024, + /* .MaxComputeWorkGroupSizeZ = */ 64, + /* .MaxComputeUniformComponents = */ 1024, + /* .MaxComputeTextureImageUnits = */ 16, + /* .MaxComputeImageUniforms = */ 8, + /* .MaxComputeAtomicCounters = */ 8, + /* .MaxComputeAtomicCounterBuffers = */ 1, + /* .MaxVaryingComponents = */ 60, + /* .MaxVertexOutputComponents = */ 64, + /* .MaxGeometryInputComponents = */ 64, + /* .MaxGeometryOutputComponents = */ 128, + /* .MaxFragmentInputComponents = */ 128, + /* .MaxImageUnits = */ 8, + /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, + /* .MaxCombinedShaderOutputResources = */ 8, + /* .MaxImageSamples = */ 0, + /* .MaxVertexImageUniforms = */ 0, + /* .MaxTessControlImageUniforms = */ 0, + /* .MaxTessEvaluationImageUniforms = */ 0, + /* .MaxGeometryImageUniforms = */ 0, + /* .MaxFragmentImageUniforms = */ 8, + /* .MaxCombinedImageUniforms = */ 8, + /* .MaxGeometryTextureImageUnits = */ 16, + /* .MaxGeometryOutputVertices = */ 256, + /* .MaxGeometryTotalOutputComponents = */ 1024, + /* .MaxGeometryUniformComponents = */ 1024, + /* .MaxGeometryVaryingComponents = */ 64, + /* .MaxTessControlInputComponents = */ 128, + /* .MaxTessControlOutputComponents = */ 128, + /* .MaxTessControlTextureImageUnits = */ 16, + /* .MaxTessControlUniformComponents = */ 1024, + /* .MaxTessControlTotalOutputComponents = */ 4096, + /* .MaxTessEvaluationInputComponents = */ 128, + /* .MaxTessEvaluationOutputComponents = */ 128, + /* .MaxTessEvaluationTextureImageUnits = */ 16, + /* .MaxTessEvaluationUniformComponents = */ 1024, + /* .MaxTessPatchComponents = */ 120, + /* .MaxPatchVertices = */ 32, + /* .MaxTessGenLevel = */ 64, + /* .MaxViewports = */ 16, + /* .MaxVertexAtomicCounters = */ 0, + /* .MaxTessControlAtomicCounters = */ 0, + /* .MaxTessEvaluationAtomicCounters = */ 0, + /* .MaxGeometryAtomicCounters = */ 0, + /* .MaxFragmentAtomicCounters = */ 8, + /* .MaxCombinedAtomicCounters = */ 8, + /* .MaxAtomicCounterBindings = */ 1, + /* .MaxVertexAtomicCounterBuffers = */ 0, + /* .MaxTessControlAtomicCounterBuffers = */ 0, + /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, + /* .MaxGeometryAtomicCounterBuffers = */ 0, + /* .MaxFragmentAtomicCounterBuffers = */ 1, + /* .MaxCombinedAtomicCounterBuffers = */ 1, + /* .MaxAtomicCounterBufferSize = */ 16384, + /* .MaxTransformFeedbackBuffers = */ 4, + /* .MaxTransformFeedbackInterleavedComponents = */ 64, + /* .MaxCullDistances = */ 8, + /* .MaxCombinedClipAndCullDistances = */ 8, + /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 4, + + /* .limits = */ TLimits{ + /* .nonInductiveForLoops = */ true, + /* .whileLoops = */ true, + /* .doWhileLoops = */ true, + /* .generalUniformIndexing = */ true, + /* .generalAttributeMatrixVectorIndexing = */ true, + /* .generalVaryingIndexing = */ true, + /* .generalSamplerIndexing = */ true, + /* .generalVariableIndexing = */ true, + /* .generalConstantMatrixVectorIndexing = */ true, + }}; diff --git a/engine/renderer/include/DirStackIncluder.h b/engine/shadercompiler/src/includer.hpp similarity index 98% rename from engine/renderer/include/DirStackIncluder.h rename to engine/shadercompiler/src/includer.hpp index f9ea572..52b03d2 100755 --- a/engine/renderer/include/DirStackIncluder.h +++ b/engine/shadercompiler/src/includer.hpp @@ -43,8 +43,6 @@ #include -#include "file.hpp" - // Default include class for normal include convention of search backward // through the stack of active include paths (for nested includes). // Can be overridden to customize. @@ -136,6 +134,7 @@ protected: // If no path markers, return current working directory. // Otherwise, strip file name and return path leading up to it. virtual std::string getDirectory(const std::string) const { - return file::get_domain_path(file::Domain::Internal).string(); + //return file::get_domain_path(file::Domain::Internal).string(); + return ""; } }; diff --git a/engine/shadercompiler/src/shadercompiler.cpp b/engine/shadercompiler/src/shadercompiler.cpp new file mode 100755 index 0000000..35f8774 --- /dev/null +++ b/engine/shadercompiler/src/shadercompiler.cpp @@ -0,0 +1,117 @@ +#include "shadercompiler.hpp" + +#include +#include +#include + +#include "log.hpp" +#include "string_utils.hpp" +#include "includer.hpp" +#include "defaultresources.hpp" + +static inline std::string include_path; + +ShaderCompiler::ShaderCompiler() { + glslang::InitializeProcess(); +} + +void ShaderCompiler::set_include_path(const std::string_view path) { + include_path = path; +} + +const std::vector compile_glsl_to_spv(const std::string_view source_string, const EShLanguage shader_language, const CompileOptions& options) { + std::string newString = "#version 430 core\n"; + + newString += "#extension GL_GOOGLE_include_directive : enable\n"; + newString += "#extension GL_GOOGLE_cpp_style_line_directive : enable\n"; + + for(auto& definition : options.definitions) + newString += "#define " + definition + "\n"; + + newString += "#line 1\n"; + + newString += source_string; + + const char* InputCString = newString.c_str(); + + glslang::TShader Shader(shader_language); + + Shader.setStrings(&InputCString, 1); + + int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 + glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_1; + glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0; + + Shader.setEnvInput(glslang::EShSourceGlsl, shader_language, glslang::EShClientVulkan, ClientInputSemanticsVersion); + Shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); + Shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion); + + TBuiltInResource Resources = DefaultTBuiltInResource; + EShMessages messages = (EShMessages) (EShMsgSpvRules); + + DirStackFileIncluder includer; + includer.pushExternalLocalDirectory(include_path); + + if (!Shader.parse(&Resources, 100, false, (EShMessages)0, includer)) { + console::error(System::Renderer, "{}", Shader.getInfoLog()); + + return {}; + } + + glslang::TProgram Program; + Program.addShader(&Shader); + + if(!Program.link(messages)) { + console::error(System::None, "Failed to link shader: {} {} {}", source_string.data(), Shader.getInfoLog(), Shader.getInfoDebugLog()); + + return {}; + } + + std::vector SpirV; + spv::SpvBuildLogger logger; + glslang::SpvOptions spvOptions; + glslang::GlslangToSpv(*Program.getIntermediate(shader_language), SpirV, &logger, &spvOptions); + + return SpirV; +} + +std::optional ShaderCompiler::compile(const ShaderLanguage from_language, const ShaderStage shader_stage, const ShaderSource& shader_source, const ShaderLanguage to_language, const CompileOptions& options) { + if(from_language != ShaderLanguage::GLSL) { + console::error(System::Renderer, "Non-supported input language!"); + return std::nullopt; + } + + EShLanguage lang = EShLangMiss; + switch(shader_stage) { + case ShaderStage::Vertex: + lang = EShLangVertex; + break; + case ShaderStage::Fragment: + lang = EShLangFragment; + break; + } + + auto spirv = compile_glsl_to_spv(shader_source.as_string(), lang, options); + if(spirv.empty()) { + console::error(System::Renderer, "SPIRV generation failed!"); + return std::nullopt; + } + +#ifdef PLATFORM_MACOS + spirv_cross::CompilerMSL msl(std::move(spirv)); + + spirv_cross::CompilerMSL::Options opts; + if(options.is_apple_mobile) { + opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; + } else { + opts.platform = spirv_cross::CompilerMSL::Options::Platform::iOS; + } + opts.enable_decoration_binding = true; + + msl.set_msl_options(opts); + + return msl.compile(); +#else + return spirv; +#endif +} diff --git a/tools/common/src/debugpass.cpp b/tools/common/src/debugpass.cpp index d1f89c0..91e7811 100755 --- a/tools/common/src/debugpass.cpp +++ b/tools/common/src/debugpass.cpp @@ -8,7 +8,7 @@ #include "gfx.hpp" #include "asset.hpp" #include "log.hpp" -#include "shadercompiler.hpp" +#include "materialcompiler.hpp" struct BillPushConstant { Matrix4x4 view, mvp; diff --git a/tools/shadercompiler/CMakeLists.txt b/tools/shadercompiler/CMakeLists.txt index 7d66079..a361993 100755 --- a/tools/shadercompiler/CMakeLists.txt +++ b/tools/shadercompiler/CMakeLists.txt @@ -1,7 +1,8 @@ -add_executable(ShaderCompiler main.cpp) -target_link_libraries(ShaderCompiler - PUBLIC - ${CROSS_LIBS} - Log) -set_engine_properties(ShaderCompiler) -set_output_dir(ShaderCompiler) +add_executable(ShaderCompilerTool main.cpp) +target_link_libraries(ShaderCompilerTool + PRIVATE + ShaderCompiler + Log + Utility) +set_engine_properties(ShaderCompilerTool) +set_output_dir(ShaderCompilerTool) diff --git a/tools/shadercompiler/main.cpp b/tools/shadercompiler/main.cpp index f097f3a..af0b45a 100755 --- a/tools/shadercompiler/main.cpp +++ b/tools/shadercompiler/main.cpp @@ -1,236 +1,86 @@ #include #include -#include -#include -#include -#include - -#include "DirStackIncluder.h" +#include "shadercompiler.hpp" #include "log.hpp" +#include "string_utils.hpp" -const TBuiltInResource DefaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 4096, - /* .MaxVaryingFloats = */ 64, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 4096, - /* .MaxDrawBuffers = */ 32, - /* .MaxVertexUniformVectors = */ 128, - /* .MaxVaryingVectors = */ 8, - /* .MaxFragmentUniformVectors = */ 16, - /* .MaxVertexOutputVectors = */ 16, - /* .MaxFragmentInputVectors = */ 15, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 16, - /* .MaxComputeImageUniforms = */ 8, - /* .MaxComputeAtomicCounters = */ 8, - /* .MaxComputeAtomicCounterBuffers = */ 1, - /* .MaxVaryingComponents = */ 60, - /* .MaxVertexOutputComponents = */ 64, - /* .MaxGeometryInputComponents = */ 64, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 8, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8, - /* .MaxCombinedShaderOutputResources = */ 8, - /* .MaxImageSamples = */ 0, - /* .MaxVertexImageUniforms = */ 0, - /* .MaxTessControlImageUniforms = */ 0, - /* .MaxTessEvaluationImageUniforms = */ 0, - /* .MaxGeometryImageUniforms = */ 0, - /* .MaxFragmentImageUniforms = */ 8, - /* .MaxCombinedImageUniforms = */ 8, - /* .MaxGeometryTextureImageUnits = */ 16, - /* .MaxGeometryOutputVertices = */ 256, - /* .MaxGeometryTotalOutputComponents = */ 1024, - /* .MaxGeometryUniformComponents = */ 1024, - /* .MaxGeometryVaryingComponents = */ 64, - /* .MaxTessControlInputComponents = */ 128, - /* .MaxTessControlOutputComponents = */ 128, - /* .MaxTessControlTextureImageUnits = */ 16, - /* .MaxTessControlUniformComponents = */ 1024, - /* .MaxTessControlTotalOutputComponents = */ 4096, - /* .MaxTessEvaluationInputComponents = */ 128, - /* .MaxTessEvaluationOutputComponents = */ 128, - /* .MaxTessEvaluationTextureImageUnits = */ 16, - /* .MaxTessEvaluationUniformComponents = */ 1024, - /* .MaxTessPatchComponents = */ 120, - /* .MaxPatchVertices = */ 32, - /* .MaxTessGenLevel = */ 64, - /* .MaxViewports = */ 16, - /* .MaxVertexAtomicCounters = */ 0, - /* .MaxTessControlAtomicCounters = */ 0, - /* .MaxTessEvaluationAtomicCounters = */ 0, - /* .MaxGeometryAtomicCounters = */ 0, - /* .MaxFragmentAtomicCounters = */ 8, - /* .MaxCombinedAtomicCounters = */ 8, - /* .MaxAtomicCounterBindings = */ 1, - /* .MaxVertexAtomicCounterBuffers = */ 0, - /* .MaxTessControlAtomicCounterBuffers = */ 0, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 0, - /* .MaxGeometryAtomicCounterBuffers = */ 0, - /* .MaxFragmentAtomicCounterBuffers = */ 1, - /* .MaxCombinedAtomicCounterBuffers = */ 1, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 4, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - /* .maxDualSourceDrawBuffersEXT = */ 4, - - /* .limits = */ TLimits{ - /* .nonInductiveForLoops = */ true, - /* .whileLoops = */ true, - /* .doWhileLoops = */ true, - /* .generalUniformIndexing = */ true, - /* .generalAttributeMatrixVectorIndexing = */ true, - /* .generalVaryingIndexing = */ true, - /* .generalSamplerIndexing = */ true, - /* .generalVariableIndexing = */ true, - /* .generalConstantMatrixVectorIndexing = */ true, - }}; - -const std::vector CompileGLSL(const std::string& filename, EShLanguage ShaderType) { - std::string newString = "#version 430 core\n"; - - newString += "#extension GL_GOOGLE_include_directive : enable\n"; - newString += "#extension GL_GOOGLE_cpp_style_line_directive : enable\n"; - - newString += "#line 1\n"; - - newString += filename; - - const char* InputCString = newString.c_str(); - - glslang::TShader Shader(ShaderType); - - Shader.setStrings(&InputCString, 1); - - int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100 - glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_1; - glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_0; - - Shader.setEnvInput(glslang::EShSourceGlsl, ShaderType, glslang::EShClientVulkan, ClientInputSemanticsVersion); - Shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion); - Shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion); - - TBuiltInResource Resources = DefaultTBuiltInResource; - EShMessages messages = (EShMessages) (EShMsgSpvRules); - - DirStackFileIncluder includer; - - if (!Shader.parse(&Resources, 100, false, messages, includer)) { - console::error(System::None, "Failed to parse shader: {} {} {}", filename, Shader.getInfoLog(), Shader.getInfoDebugLog()); - - return {}; - } - - glslang::TProgram Program; - Program.addShader(&Shader); - - if(!Program.link(messages)) { - console::error(System::None, "Failed to link shader: {} {} {}", filename, Shader.getInfoLog(), Shader.getInfoDebugLog()); - - return {}; - } - - std::vector SpirV; - spv::SpvBuildLogger logger; - glslang::SpvOptions spvOptions; - glslang::GlslangToSpv(*Program.getIntermediate(ShaderType), SpirV, &logger, &spvOptions); - - return SpirV; +bool has_extension(const std::filesystem::path path, const std::string_view extension) { + return string_contains(path.filename().string(), extension); } int main(int argc, char* argv[]) { - if(argc < 2) + if(argc < 2) { + console::error(System::Core, "Not enough arguments!"); return -1; + } - glslang::InitializeProcess(); + shader_compiler.set_include_path(std::filesystem::current_path().string()); + + std::filesystem::path source_path = argv[1]; + std::filesystem::path destination_path = argv[2]; - std::ifstream t(argv[1]); + std::ifstream t(source_path); std::stringstream buffer; buffer << t.rdbuf(); - if(std::string(argv[1]).find("nocompile") != std::string::npos) { + if(has_extension(source_path, "nocompile")) { std::string outname = argv[2]; outname = outname.substr(0, outname.length() - 5); // remove .glsl outname = outname.substr(0, outname.length() - 10); // remove .nocompile std::ofstream out(outname + ".glsl"); out << buffer.rdbuf(); + + console::info(System::Core, "Successfully written {} to {}.", source_path, destination_path); + + return 0; } else { - EShLanguage lang; - if (std::string(argv[1]).find("vert") != std::string::npos) { - lang = EShLangVertex; + ShaderStage stage; + if(has_extension(source_path, ".vert")) + stage = ShaderStage::Vertex; + else + stage = ShaderStage::Fragment; + + ShaderLanguage language; + CompileOptions options; +#ifdef PLATFORM_MACOS + options.is_apple_mobile = (bool)argv[3]; + + language = ShaderLanguage::MSL; + destination_path.replace_extension(".msl"); +#else + language = ShaderLanguage::SPIRV; + destination_path.replace_extension(".spv"); +#endif + + const auto compiled_source = shader_compiler.compile(ShaderLanguage::GLSL, stage, buffer.str(), language, options); + if(!compiled_source.has_value()) { + console::error(System::Core, "Error when compiling {}!", source_path); + return -1; } - else { - lang = EShLangFragment; + + switch(language) { + case ShaderLanguage::SPIRV: + { + const auto spirv = compiled_source->as_bytecode(); + + std::ofstream out(destination_path, std::ios::binary); // remove .glsl + out.write((char*)spirv.data(), spirv.size() * sizeof(uint32_t)); + } + break; + case ShaderLanguage::MSL: + { + std::ofstream out(destination_path); // remove .glsl + out << compiled_source->as_string(); + } + break; + default: + break; } - - std::string outname = argv[2]; - outname = outname.substr(0, outname.length() - 5); - - // generate msl - #ifdef PLATFORM_MACOS - bool is_ios = (bool)argv[3]; - - { - auto vertexSPIRV = CompileGLSL(buffer.str(), lang); - if (vertexSPIRV.size() == 0) - return -1; - - spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); - - spirv_cross::CompilerMSL::Options opts; - opts.platform = is_ios ? spirv_cross::CompilerMSL::Options::Platform::iOS : spirv_cross::CompilerMSL::Options::Platform::macOS; - opts.enable_decoration_binding = true; - - msl.set_msl_options(opts); - - std::string s = msl.compile(); - - std::ofstream out(outname + ".msl"); // remove .glsl - out << s; - } - #else - // generate spv - { - auto vertexSPIRV = CompileGLSL(buffer.str(), lang); - if (vertexSPIRV.size() == 0) - return -1; - - std::ofstream out(outname + ".spv", std::ios::binary); // remove .glsl - out.write((char*)vertexSPIRV.data(), vertexSPIRV.size() * sizeof(uint32_t)); - } - #endif + + console::info(System::Core, "Successfully written shader from {} to {}.", source_path, destination_path); + + return 0; } - - return 0; }