Fix vulkan shader loading and runtime compilation
This commit is contained in:
parent
46628c6376
commit
c42bde8830
9 changed files with 64 additions and 31 deletions
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Reference in a new issue