diff --git a/.idea/.name b/.idea/.name index d8662b5..f081644 100644 --- a/.idea/.name +++ b/.idea/.name @@ -1 +1 @@ -OpenVulkano +openVulkanoCpp \ No newline at end of file diff --git a/cmake/SetupVulkan.cmake b/cmake/SetupVulkan.cmake index a880584..b386f3a 100644 --- a/cmake/SetupVulkan.cmake +++ b/cmake/SetupVulkan.cmake @@ -4,7 +4,17 @@ function(SetupVulkan TARGET) target_link_libraries(${TARGET} PRIVATE ${MoltenVK_LIBRARIES}) else () find_package(Vulkan REQUIRED) + get_filename_component(Vulkan_SDK_DIR "${Vulkan_LIBRARIES}" DIRECTORY) # Get VulkanSDK/[version]/Bin target_link_libraries(${TARGET} PRIVATE Vulkan::Vulkan) + if(CMAKE_BUILD_TYPE MATCHES "Debug") + target_link_libraries(${TARGET} PRIVATE "${Vulkan_SDK_DIR}/shaderc_combinedd.lib" + "${Vulkan_SDK_DIR}/spirv-cross-cored.lib" "${Vulkan_SDK_DIR}/spirv-cross-glsld.lib" + "${Vulkan_SDK_DIR}/spirv-cross-hlsld.lib") + else() + target_link_libraries(${TARGET} PRIVATE "${Vulkan_SDK_DIR}/shaderc_combined.lib" + "${Vulkan_SDK_DIR}/spirv-cross-core.lib" "${Vulkan_SDK_DIR}/spirv-cross-glsl.lib" + "${Vulkan_SDK_DIR}/spirv-cross-hlsl.lib") + endif() endif () target_include_directories(${TARGET} PUBLIC ${Vulkan_INCLUDE_DIR}) @@ -17,4 +27,5 @@ function(SetupVulkan TARGET) find_package(XCB REQUIRED) target_link_libraries(${TARGET} PRIVATE ${XCB_LIBRARIES}) endif() -endfunction() \ No newline at end of file +endfunction() + diff --git a/examples/main.cpp b/examples/main.cpp index 18a8431..ed4ab7d 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -17,10 +17,17 @@ #include #include +#include "Shader/ShaderCompiler.hpp" + using namespace OpenVulkano; int main(int argc, char** argv) { + // TEST CASE + if (false) + ShaderCompiler::CompileGLSLToSpirv(R"(D:\Projects\OpenVulkano\openVulkanoCpp\Shader\grid.vert)", "", "main", + shaderc_vertex_shader, false); + std::vector examples = { "Cubes Example App", "Moving Cube Example App", diff --git a/openVulkanoCpp/Shader/ShaderCompiler.cpp b/openVulkanoCpp/Shader/ShaderCompiler.cpp new file mode 100644 index 0000000..c2113fc --- /dev/null +++ b/openVulkanoCpp/Shader/ShaderCompiler.cpp @@ -0,0 +1,100 @@ +#include "ShaderCompiler.hpp" + +namespace OpenVulkano +{ + Unique ShaderCompiler::CompileGLSLToSpirv(const std::string& absPath, const std::string& incPath, + const std::string& entryPoint, shaderc_shader_kind shaderStage, + bool bHaveIncludes) + { + Array file = Utils::ReadFile(absPath, false, true); + +#if defined(_DEBUG) + printf("Compiling shader: %s\n", absPath.c_str()); + printf("%s\n", file.Data() + 1); +#endif + + shaderc::Compiler shaderCompiler; + shaderc::CompileOptions options; + + if (bHaveIncludes) options.SetIncluder(std::make_unique(incPath)); + options.SetSourceLanguage(shaderc_source_language_glsl); + options.SetSuppressWarnings(); + + shaderc::PreprocessedSourceCompilationResult preResult = + shaderCompiler.PreprocessGlsl(file.Data(), shaderStage, entryPoint.c_str(), options); + + if (preResult.GetCompilationStatus() != shaderc_compilation_status_success) + { + throw std::runtime_error("Failed to preprocess shader: " + preResult.GetErrorMessage()); + return nullptr; + } + + shaderc::CompilationResult result = + shaderCompiler.CompileGlslToSpv(static_cast(preResult.begin()), shaderStage, "", options); + + if (result.GetCompilationStatus() != shaderc_compilation_status_success) + { + throw std::runtime_error("Failed to compile shader: " + result.GetErrorMessage()); + return nullptr; + } + + Unique spirv = std::make_unique((void*) result.begin()); + return spirv; + } + + ShaderIncluder::ShaderIncluder(const std::string& path) + { + // TODO : Add the path to your include folder + m_includes.push_back(path); + } + + shaderc_include_result* ShaderIncluder::GetInclude(const char* requested_source, shaderc_include_type type, + const char* requesting_source, uint64_t include_depth) + { + const char* includePath = GetActualPath(requested_source); + const char* content = RecordInclude(includePath); + + shaderc_include_result* result = new shaderc_include_result(); + result->content = content; + result->content_length = strlen(content); + result->source_name = includePath; + result->source_name_length = strlen(includePath); + result->user_data = nullptr; + + return result; + } + + void ShaderIncluder::ReleaseInclude(shaderc_include_result* data) { delete data; } + + std::string ShaderIncluder::ResolveInclude(const std::string requestedSource) + { + // Check if the file exists in the include paths + for (const std::string& includePath: m_includes) + { + std::string path = includePath + requestedSource; + return path; + } + + return ""; + } + + const char* ShaderIncluder::RecordInclude(const std::string& requestedSource) + { + Array data = Utils::ReadFile(requestedSource); + + char* result = new char[data.Size() + 1]; + strcpy_s(result, data.Size(), data.Data()); + + return result; + } + + const char* ShaderIncluder::GetActualPath(const std::string& requestedSource) + { + std::string includePath = ResolveInclude(requestedSource); + + char* result = new char[includePath.size() + 1]; + strcpy_s(result, includePath.size(), includePath.c_str()); + + return result; + } +} diff --git a/openVulkanoCpp/Shader/ShaderCompiler.hpp b/openVulkanoCpp/Shader/ShaderCompiler.hpp new file mode 100644 index 0000000..b4d083d --- /dev/null +++ b/openVulkanoCpp/Shader/ShaderCompiler.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "Base/Utils.hpp" +#include "Base/Wrapper.hpp" + +#include +#include +#include + +namespace OpenVulkano +{ + class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface + { + public: + ShaderIncluder(const std::string& path); + ~ShaderIncluder() override = default; + + shaderc_include_result* GetInclude(const char* requested_source, shaderc_include_type type, + const char* requesting_source, uint64_t include_depth) override; + void ReleaseInclude(shaderc_include_result* data) override; + + private: + std::string ResolveInclude(const std::string requestedSource); + const char* RecordInclude(const std::string& requestedSource); + const char* GetActualPath(const std::string& requestedSource); + + private: + std::vector m_includes; + }; + + class ShaderCompiler + { + public: + /** + * @param absPath - absolute path of the shader that needs to be compiled + * @param incPath - include path that will be used to resolve includes + * @param entryPoint - the name of the void function in the shader + * @param shaderStage - type of the shader that needs to be compiled + * @param bHaveIncludes - if incPath is empty, make it false + */ + static Unique CompileGLSLToSpirv(const std::string& absPath, + const std::string& incPath, const std::string& entryPoint, + shaderc_shader_kind shaderStage, bool bHaveIncludes); + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp b/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp index 86c1629..998a7fc 100644 --- a/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp +++ b/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp @@ -27,6 +27,10 @@ namespace OpenVulkano::Vulkan vk::MemoryPropertyFlags properties; void* mapped = nullptr; + ManagedBuffer(MemoryAllocation* alloc, vk::DeviceSize offset, vk::DeviceSize size, vk::Buffer buffer, vk::BufferUsageFlags usageFlags, vk::MemoryPropertyFlags memProperties) + : allocation(alloc), offset(offset), size(size), buffer(buffer), usage(usageFlags), properties(memProperties), mapped(nullptr) + {} + ~ManagedBuffer() { allocation->device.destroy(buffer); diff --git a/openVulkanoCpp/Vulkan/Resources/MemoryPool.cpp b/openVulkanoCpp/Vulkan/Resources/MemoryPool.cpp index 6fe32c5..4292dc3 100644 --- a/openVulkanoCpp/Vulkan/Resources/MemoryPool.cpp +++ b/openVulkanoCpp/Vulkan/Resources/MemoryPool.cpp @@ -131,7 +131,7 @@ namespace OpenVulkano::Vulkan uint32_t offset = Utils::Align(allocation->used, memoryRequirements.alignment); device->device.bindBufferMemory(buffer, allocation->memory, offset); allocation->used += size + (offset - allocation->used); - return ManagedBufferPtr{ new ManagedBuffer({allocation, offset, size, buffer, usage, properties, nullptr}) }; + return ManagedBufferPtr{ new ManagedBuffer(allocation, offset, size, buffer, usage, properties) }; } MemoryPool::ManagedBufferPtr MemoryPool::CreateSharedMemoryBuffer(size_t size) @@ -150,4 +150,9 @@ namespace OpenVulkano::Vulkan } return CreateBuffer(size, vk::BufferUsageFlagBits::eVertexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent/* | vk::MemoryPropertyFlagBits::eDeviceLocal*/); } + + void ManagedBufferDeleter::operator()(ManagedBuffer* buffer) + { + MemoryPool::ReleaseBuffer(buffer); + } } diff --git a/openVulkanoCpp/Vulkan/Resources/MemoryPool.hpp b/openVulkanoCpp/Vulkan/Resources/MemoryPool.hpp index abd75df..2d5129e 100644 --- a/openVulkanoCpp/Vulkan/Resources/MemoryPool.hpp +++ b/openVulkanoCpp/Vulkan/Resources/MemoryPool.hpp @@ -17,7 +17,11 @@ namespace OpenVulkano::Vulkan class Device; class MemoryAllocation; class ManagedBuffer; - struct ManagedBufferDeleter; + + struct ManagedBufferDeleter + { + void operator()(ManagedBuffer* buffer); + }; class MemoryPool { @@ -55,12 +59,4 @@ namespace OpenVulkano::Vulkan static void ReleaseBuffer(ManagedBuffer* buffer); }; - - struct ManagedBufferDeleter - { - void operator()(ManagedBuffer* buffer) - { - MemoryPool::ReleaseBuffer(buffer); - } - }; } \ No newline at end of file