From c42bde8830423c7f33889e5242806b13e4e8d89b Mon Sep 17 00:00:00 2001 From: redstrate <54911369+redstrate@users.noreply.github.com> Date: Fri, 14 Aug 2020 17:45:51 -0400 Subject: [PATCH] Fix vulkan shader loading and runtime compilation --- engine/core/include/file.hpp | 3 +- engine/core/src/file.cpp | 2 + engine/gfx/public/gfx.hpp | 4 +- engine/gfx/vulkan/include/gfx_vulkan.hpp | 2 +- engine/gfx/vulkan/src/gfx_vulkan.cpp | 45 +++++++++++++++------- engine/renderer/include/shadercompiler.hpp | 2 +- engine/renderer/src/shadercompiler.cpp | 30 +++++++++------ platforms/windows/CMakeLists.txt | 3 ++ platforms/windows/file.cpp | 4 +- 9 files changed, 64 insertions(+), 31 deletions(-) diff --git a/engine/core/include/file.hpp b/engine/core/include/file.hpp index c266e0a..8130457 100755 --- a/engine/core/include/file.hpp +++ b/engine/core/include/file.hpp @@ -27,7 +27,8 @@ namespace file { data(std::move(f.data)) {} ~File() { - fclose(handle); + if(handle != nullptr) + fclose(handle); } /** Loads a type. diff --git a/engine/core/src/file.cpp b/engine/core/src/file.cpp index 8e4ef99..6905dfe 100755 --- a/engine/core/src/file.cpp +++ b/engine/core/src/file.cpp @@ -1,5 +1,7 @@ #include "file.hpp" +#include + #include "string_utils.hpp" #include "log.hpp" #include "assertions.hpp" diff --git a/engine/gfx/public/gfx.hpp b/engine/gfx/public/gfx.hpp index c3ffc11..b276038 100755 --- a/engine/gfx/public/gfx.hpp +++ b/engine/gfx/public/gfx.hpp @@ -2,6 +2,7 @@ #include #include +#include class GFXBuffer; class GFXPipeline; @@ -143,7 +144,8 @@ struct GFXGraphicsPipelineCreateInfo { struct Shaders { std::string_view vertex_path, fragment_path; - std::string vertex_src, fragment_src; + + std::variant> vertex_src, fragment_src; GFXShaderConstants vertex_constants, fragment_constants; } shaders; diff --git a/engine/gfx/vulkan/include/gfx_vulkan.hpp b/engine/gfx/vulkan/include/gfx_vulkan.hpp index 27a5e46..7534a3b 100755 --- a/engine/gfx/vulkan/include/gfx_vulkan.hpp +++ b/engine/gfx/vulkan/include/gfx_vulkan.hpp @@ -68,7 +68,7 @@ private: uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout); - VkShaderModule createShaderModule(const unsigned char* code, const int length); + VkShaderModule createShaderModule(const uint32_t* code, const int length); VkCommandBuffer beginSingleTimeCommands(); void endSingleTimeCommands(VkCommandBuffer commandBuffer); diff --git a/engine/gfx/vulkan/src/gfx_vulkan.cpp b/engine/gfx/vulkan/src/gfx_vulkan.cpp index 7512d0a..d0bd4ab 100755 --- a/engine/gfx/vulkan/src/gfx_vulkan.cpp +++ b/engine/gfx/vulkan/src/gfx_vulkan.cpp @@ -541,17 +541,36 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate vkDeviceWaitIdle(device); - // setup shader modules - auto vertex_shader = file::open(file::internal_domain / (std::string(info.shaders.vertex_path) + ".spv")); - vertex_shader->read_all(); + VkShaderModule vertex_module = VK_NULL_HANDLE, fragment_module = VK_NULL_HANDLE; - auto fragment_shader = file::open(file::internal_domain / (std::string(info.shaders.fragment_path) + ".spv")); - fragment_shader->read_all(); + const bool vertex_use_shader_source = info.shaders.vertex_path.empty(); + const bool fragment_use_shader_source = info.shaders.fragment_path.empty(); + + if (vertex_use_shader_source) { + auto& vertex_shader_vector = std::get>(info.shaders.vertex_src); + + vertex_module = createShaderModule(vertex_shader_vector.data(), vertex_shader_vector.size() * sizeof(uint32_t)); + } + else { + auto vertex_shader = file::open(file::internal_domain / (std::string(info.shaders.vertex_path) + ".spv")); + vertex_shader->read_all(); + + vertex_module = createShaderModule(vertex_shader->cast_data(), vertex_shader->size()); + } + + if (fragment_use_shader_source) { + auto& fragment_shader_vector = std::get>(info.shaders.fragment_src); + + fragment_module = createShaderModule(fragment_shader_vector.data(), fragment_shader_vector.size() * sizeof(uint32_t)); + } + else { + auto fragment_shader = file::open(file::internal_domain / (std::string(info.shaders.fragment_path) + ".spv")); + fragment_shader->read_all(); + + fragment_module = createShaderModule(fragment_shader->cast_data(), fragment_shader->size()); + } - auto vertex_module = createShaderModule(vertex_shader->cast_data(), vertex_shader->size()); name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)vertex_module, info.shaders.vertex_path); - - auto fragment_module = createShaderModule(fragment_shader->cast_data(), fragment_shader->size()); name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)fragment_module, info.shaders.fragment_path); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; @@ -754,15 +773,13 @@ GFXSize GFXVulkan::get_alignment(GFXSize size) { return (size + minUboAlignment / 2) & ~int(minUboAlignment - 1); } -void GFXVulkan::submit(GFXCommandBuffer *command_buffer, const int identifier) { +void GFXVulkan::submit(GFXCommandBuffer* command_buffer, const int identifier) { vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits::max()); uint32_t imageIndex = 0; VkResult result = vkAcquireNextImageKHR(device, swapchain, std::numeric_limits::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - //std::cout << "oops??" << std::endl; + if (result == VK_ERROR_OUT_OF_DATE_KHR) return; - } VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -1004,7 +1021,7 @@ VkResult CreateDebugUtilsMessengerEXT( void GFXVulkan::createInstance(std::vector layers, std::vector extensions) { VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT ; debugCreateInfo.pfnUserCallback = DebugCallback; // global function @@ -1476,7 +1493,7 @@ void GFXVulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageAsp endSingleTimeCommands(commandBuffer); } -VkShaderModule GFXVulkan::createShaderModule(const unsigned char* code, const int length) { +VkShaderModule GFXVulkan::createShaderModule(const uint32_t* code, const int length) { VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = length; diff --git a/engine/renderer/include/shadercompiler.hpp b/engine/renderer/include/shadercompiler.hpp index c7bf18f..79a5a5c 100755 --- a/engine/renderer/include/shadercompiler.hpp +++ b/engine/renderer/include/shadercompiler.hpp @@ -21,7 +21,7 @@ public: // generates static and skinned versions of the pipeline provided std::tuple create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only = false); - std::string compile_material_fragment(Material& material, bool use_ibl = true); + std::variant> compile_material_fragment(Material& material, bool use_ibl = true); }; static ShaderCompiler shader_compiler; diff --git a/engine/renderer/src/shadercompiler.cpp b/engine/renderer/src/shadercompiler.cpp index 0f9c7bb..396ed6b 100755 --- a/engine/renderer/src/shadercompiler.cpp +++ b/engine/renderer/src/shadercompiler.cpp @@ -186,7 +186,7 @@ const std::vector CompileGLSL(const std::string& filename, EShLang return SpirV; } -std::string get_shader(std::string filename, bool skinned, bool cubemap) { +std::variant> get_shader(std::string filename, bool skinned, bool cubemap) { auto shader_file = file::open(file::internal_domain / filename); if(!shader_file) { std::cerr << "Failed to open " << filename << "!!" << std::endl; @@ -202,15 +202,19 @@ std::string get_shader(std::string filename, bool skinned, bool cubemap) { auto vertexSPIRV = CompileGLSL(shader_file->read_as_string(), lang, skinned, cubemap); +#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 } GFXPipeline* ShaderCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) { @@ -218,8 +222,7 @@ GFXPipeline* ShaderCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInf std::string vertex_path = createInfo.shaders.vertex_path.data(); vertex_path += ".glsl"; - std::string vertex_src = get_shader(vertex_path, false, cubemap); - createInfo.shaders.vertex_src = vertex_src; + createInfo.shaders.vertex_src = get_shader(vertex_path, false, cubemap); createInfo.shaders.vertex_path = ""; if(positions_only) { @@ -258,8 +261,7 @@ GFXPipeline* ShaderCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateIn std::string vertex_path = createInfo.shaders.vertex_path.data(); vertex_path += ".glsl"; - std::string vertex_src = get_shader(vertex_path, true, false); - createInfo.shaders.vertex_src = vertex_src; + createInfo.shaders.vertex_src = get_shader(vertex_path, true, false); createInfo.shaders.vertex_path = ""; if(positions_only) { @@ -371,7 +373,7 @@ layout(push_constant, binding = 0) uniform PushConstant {\n \ int materialOffset;\n \ };\n"; -std::string ShaderCompiler::compile_material_fragment(Material& material, bool use_ibl) { +std::variant> ShaderCompiler::compile_material_fragment(Material& material, bool use_ibl) { walked_nodes.clear(); if(!render_options.enable_ibl) @@ -576,13 +578,17 @@ std::string ShaderCompiler::compile_material_fragment(Material& material, bool u 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 } diff --git a/platforms/windows/CMakeLists.txt b/platforms/windows/CMakeLists.txt index 56be10f..c6104dc 100755 --- a/platforms/windows/CMakeLists.txt +++ b/platforms/windows/CMakeLists.txt @@ -17,4 +17,7 @@ add_custom_target(PlatformWindows_IDE SOURCES function(add_platform_commands target) set_target_properties(${target} PROPERTIES LINK_FLAGS /SUBSYSTEM:WINDOWS) + + add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $/shaders) + add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $/data) endfunction() diff --git a/platforms/windows/file.cpp b/platforms/windows/file.cpp index 8a71936..fb574ea 100755 --- a/platforms/windows/file.cpp +++ b/platforms/windows/file.cpp @@ -1,7 +1,9 @@ #include "file.hpp" +#include "string_utils.hpp" + void file::set_domain_path(const file::Domain domain, const file::Path path) { - domain_data[(int)domain] = path.string(); + domain_data[(int)domain] = replace_substring(path.string(), "{resource_dir}", "."); } file::Path file::get_writeable_directory() {