Archived
1
Fork 0

Fix vulkan shader loading and runtime compilation

This commit is contained in:
redstrate 2020-08-14 17:45:51 -04:00
parent 46628c6376
commit c42bde8830
9 changed files with 64 additions and 31 deletions

View file

@ -27,7 +27,8 @@ namespace file {
data(std::move(f.data)) {} data(std::move(f.data)) {}
~File() { ~File() {
fclose(handle); if(handle != nullptr)
fclose(handle);
} }
/** Loads a type. /** Loads a type.

View file

@ -1,5 +1,7 @@
#include "file.hpp" #include "file.hpp"
#include <cstdio>
#include "string_utils.hpp" #include "string_utils.hpp"
#include "log.hpp" #include "log.hpp"
#include "assertions.hpp" #include "assertions.hpp"

View file

@ -2,6 +2,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <variant>
class GFXBuffer; class GFXBuffer;
class GFXPipeline; class GFXPipeline;
@ -143,7 +144,8 @@ struct GFXGraphicsPipelineCreateInfo {
struct Shaders { struct Shaders {
std::string_view vertex_path, fragment_path; std::string_view vertex_path, fragment_path;
std::string vertex_src, fragment_src;
std::variant<std::string, std::vector<uint32_t>> vertex_src, fragment_src;
GFXShaderConstants vertex_constants, fragment_constants; GFXShaderConstants vertex_constants, fragment_constants;
} shaders; } shaders;

View file

@ -68,7 +68,7 @@ private:
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
void transitionImageLayout(VkImage image, VkFormat format, VkImageAspectFlags aspect, VkImageLayout oldLayout, VkImageLayout newLayout); 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(); VkCommandBuffer beginSingleTimeCommands();
void endSingleTimeCommands(VkCommandBuffer commandBuffer); void endSingleTimeCommands(VkCommandBuffer commandBuffer);

View file

@ -541,17 +541,36 @@ GFXPipeline* GFXVulkan::create_graphics_pipeline(const GFXGraphicsPipelineCreate
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
// setup shader modules VkShaderModule vertex_module = VK_NULL_HANDLE, fragment_module = VK_NULL_HANDLE;
auto vertex_shader = file::open(file::internal_domain / (std::string(info.shaders.vertex_path) + ".spv"));
vertex_shader->read_all();
auto fragment_shader = file::open(file::internal_domain / (std::string(info.shaders.fragment_path) + ".spv")); const bool vertex_use_shader_source = info.shaders.vertex_path.empty();
fragment_shader->read_all(); const bool fragment_use_shader_source = info.shaders.fragment_path.empty();
if (vertex_use_shader_source) {
auto& vertex_shader_vector = std::get<std::vector<uint32_t>>(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<uint32_t>(), vertex_shader->size());
}
if (fragment_use_shader_source) {
auto& fragment_shader_vector = std::get<std::vector<uint32_t>>(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<uint32_t>(), fragment_shader->size());
}
auto vertex_module = createShaderModule(vertex_shader->cast_data<unsigned char>(), vertex_shader->size());
name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)vertex_module, info.shaders.vertex_path); name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)vertex_module, info.shaders.vertex_path);
auto fragment_module = createShaderModule(fragment_shader->cast_data<unsigned char>(), fragment_shader->size());
name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)fragment_module, info.shaders.fragment_path); name_object(device, VK_OBJECT_TYPE_SHADER_MODULE, (uint64_t)fragment_module, info.shaders.fragment_path);
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
@ -754,15 +773,13 @@ GFXSize GFXVulkan::get_alignment(GFXSize size) {
return (size + minUboAlignment / 2) & ~int(minUboAlignment - 1); 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<uint64_t>::max()); vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits<uint64_t>::max());
uint32_t imageIndex = 0; uint32_t imageIndex = 0;
VkResult result = vkAcquireNextImageKHR(device, swapchain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); VkResult result = vkAcquireNextImageKHR(device, swapchain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR)
//std::cout << "oops??" << std::endl;
return; return;
}
VkCommandBufferBeginInfo beginInfo = {}; VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@ -1004,7 +1021,7 @@ VkResult CreateDebugUtilsMessengerEXT(
void GFXVulkan::createInstance(std::vector<const char*> layers, std::vector<const char*> extensions) { void GFXVulkan::createInstance(std::vector<const char*> layers, std::vector<const char*> extensions) {
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {};
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; 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.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 debugCreateInfo.pfnUserCallback = DebugCallback; // global function
@ -1476,7 +1493,7 @@ void GFXVulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageAsp
endSingleTimeCommands(commandBuffer); endSingleTimeCommands(commandBuffer);
} }
VkShaderModule GFXVulkan::createShaderModule(const unsigned char* code, const int length) { VkShaderModule GFXVulkan::createShaderModule(const uint32_t* code, const int length) {
VkShaderModuleCreateInfo createInfo = {}; VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = length; createInfo.codeSize = length;

View file

@ -21,7 +21,7 @@ public:
// generates static and skinned versions of the pipeline provided // generates static and skinned versions of the pipeline provided
std::tuple<GFXPipeline*, GFXPipeline*> create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only = false); std::tuple<GFXPipeline*, GFXPipeline*> create_pipeline_permutations(GFXGraphicsPipelineCreateInfo& createInfo, bool positions_only = false);
std::string compile_material_fragment(Material& material, bool use_ibl = true); std::variant<std::string, std::vector<uint32_t>> compile_material_fragment(Material& material, bool use_ibl = true);
}; };
static ShaderCompiler shader_compiler; static ShaderCompiler shader_compiler;

View file

@ -186,7 +186,7 @@ const std::vector<unsigned int> CompileGLSL(const std::string& filename, EShLang
return SpirV; return SpirV;
} }
std::string get_shader(std::string filename, bool skinned, bool cubemap) { std::variant<std::string, std::vector<uint32_t>> get_shader(std::string filename, bool skinned, bool cubemap) {
auto shader_file = file::open(file::internal_domain / filename); auto shader_file = file::open(file::internal_domain / filename);
if(!shader_file) { if(!shader_file) {
std::cerr << "Failed to open " << filename << "!!" << std::endl; 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); auto vertexSPIRV = CompileGLSL(shader_file->read_as_string(), lang, skinned, cubemap);
#ifdef PLATFORM_MACOS
spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); spirv_cross::CompilerMSL msl(std::move(vertexSPIRV));
spirv_cross::CompilerMSL::Options opts; spirv_cross::CompilerMSL::Options opts;
opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS;
opts.enable_decoration_binding = true; opts.enable_decoration_binding = true;
msl.set_msl_options(opts); msl.set_msl_options(opts);
return msl.compile(); return msl.compile();
#else
return vertexSPIRV;
#endif
} }
GFXPipeline* ShaderCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) { 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(); std::string vertex_path = createInfo.shaders.vertex_path.data();
vertex_path += ".glsl"; vertex_path += ".glsl";
std::string vertex_src = get_shader(vertex_path, false, cubemap); createInfo.shaders.vertex_src = get_shader(vertex_path, false, cubemap);
createInfo.shaders.vertex_src = vertex_src;
createInfo.shaders.vertex_path = ""; createInfo.shaders.vertex_path = "";
if(positions_only) { if(positions_only) {
@ -258,8 +261,7 @@ GFXPipeline* ShaderCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreateIn
std::string vertex_path = createInfo.shaders.vertex_path.data(); std::string vertex_path = createInfo.shaders.vertex_path.data();
vertex_path += ".glsl"; vertex_path += ".glsl";
std::string vertex_src = get_shader(vertex_path, true, false); createInfo.shaders.vertex_src = get_shader(vertex_path, true, false);
createInfo.shaders.vertex_src = vertex_src;
createInfo.shaders.vertex_path = ""; createInfo.shaders.vertex_path = "";
if(positions_only) { if(positions_only) {
@ -371,7 +373,7 @@ layout(push_constant, binding = 0) uniform PushConstant {\n \
int materialOffset;\n \ int materialOffset;\n \
};\n"; };\n";
std::string ShaderCompiler::compile_material_fragment(Material& material, bool use_ibl) { std::variant<std::string, std::vector<uint32_t>> ShaderCompiler::compile_material_fragment(Material& material, bool use_ibl) {
walked_nodes.clear(); walked_nodes.clear();
if(!render_options.enable_ibl) 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); auto vertexSPIRV = CompileGLSL(src, EShLangFragment, false, false);
#ifdef PLATFORM_MACOS
spirv_cross::CompilerMSL msl(std::move(vertexSPIRV)); spirv_cross::CompilerMSL msl(std::move(vertexSPIRV));
spirv_cross::CompilerMSL::Options opts; spirv_cross::CompilerMSL::Options opts;
opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS; opts.platform = spirv_cross::CompilerMSL::Options::Platform::macOS;
opts.enable_decoration_binding = true; opts.enable_decoration_binding = true;
msl.set_msl_options(opts); msl.set_msl_options(opts);
return msl.compile(); return msl.compile();
#else
return vertexSPIRV;
#endif
} }

View file

@ -17,4 +17,7 @@ add_custom_target(PlatformWindows_IDE SOURCES
function(add_platform_commands target) function(add_platform_commands target)
set_target_properties(${target} PROPERTIES set_target_properties(${target} PROPERTIES
LINK_FLAGS /SUBSYSTEM:WINDOWS) LINK_FLAGS /SUBSYSTEM:WINDOWS)
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/shaders $<TARGET_FILE_DIR:${target}>/shaders)
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/data $<TARGET_FILE_DIR:${target}>/data)
endfunction() endfunction()

View file

@ -1,7 +1,9 @@
#include "file.hpp" #include "file.hpp"
#include "string_utils.hpp"
void file::set_domain_path(const file::Domain domain, const file::Path path) { 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() { file::Path file::get_writeable_directory() {