From 5aa84db3e25108c13134be0fe1bc29b63e825035 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Mon, 15 Jul 2024 17:30:29 +0300 Subject: [PATCH 01/14] utils::ReadFile nullTerminateString addition --- openVulkanoCpp/Base/Utils.cpp | 6 ++++-- openVulkanoCpp/Base/Utils.hpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openVulkanoCpp/Base/Utils.cpp b/openVulkanoCpp/Base/Utils.cpp index d3f8fd1..a028fe6 100644 --- a/openVulkanoCpp/Base/Utils.cpp +++ b/openVulkanoCpp/Base/Utils.cpp @@ -61,7 +61,7 @@ namespace OpenVulkano #endif } - Array Utils::ReadFile(const std::string& filePath, bool emptyOnMissing) + Array Utils::ReadFile(const std::string& filePath, bool emptyOnMissing, bool nullTerminateString) { std::ifstream file(filePath, std::ios::ate | std::ios::binary); if (!file.is_open()) @@ -69,7 +69,9 @@ namespace OpenVulkano if (emptyOnMissing) return {}; throw std::runtime_error("Failed to open file '" + filePath + "'!"); } - const size_t fileSize = static_cast(file.tellg()); + size_t fileSize = static_cast(file.tellg()); + if (nullTerminateString) fileSize++; + Array data(fileSize); file.seekg(0); file.read(data.Data(), fileSize); diff --git a/openVulkanoCpp/Base/Utils.hpp b/openVulkanoCpp/Base/Utils.hpp index a29ea03..391a322 100644 --- a/openVulkanoCpp/Base/Utils.hpp +++ b/openVulkanoCpp/Base/Utils.hpp @@ -159,7 +159,8 @@ namespace OpenVulkano return subs; } - static Array ReadFile(const std::string& filePath, bool emptyOnMissing = false); + static Array ReadFile(const std::string& filePath, bool emptyOnMissing = false, + bool nullTerminateString = false); template static int GetUniqueTypeId() From 2b36969a84f39698c05f99605a640ef3d9e7178d Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Mon, 15 Jul 2024 17:31:02 +0300 Subject: [PATCH 02/14] Runtime ShaderCompilation with Include Features --- .idea/.name | 2 +- cmake/SetupVulkan.cmake | 13 ++- examples/main.cpp | 7 ++ openVulkanoCpp/Shader/ShaderCompiler.cpp | 100 ++++++++++++++++++ openVulkanoCpp/Shader/ShaderCompiler.hpp | 45 ++++++++ .../Vulkan/Resources/ManagedBuffer.hpp | 4 + .../Vulkan/Resources/MemoryPool.cpp | 7 +- .../Vulkan/Resources/MemoryPool.hpp | 14 +-- 8 files changed, 180 insertions(+), 12 deletions(-) create mode 100644 openVulkanoCpp/Shader/ShaderCompiler.cpp create mode 100644 openVulkanoCpp/Shader/ShaderCompiler.hpp 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 From 97518bd57b83c46f74d2acaf8153cc99b304a68e Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Tue, 16 Jul 2024 11:08:00 +0300 Subject: [PATCH 03/14] dead skin removal at main.cpp --- examples/main.cpp | 5 ----- openVulkanoCpp/Shader/ShaderCompiler.cpp | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/main.cpp b/examples/main.cpp index ed4ab7d..c0a103b 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -23,11 +23,6 @@ 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 index c2113fc..2f24c67 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.cpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.cpp @@ -72,6 +72,7 @@ namespace OpenVulkano for (const std::string& includePath: m_includes) { std::string path = includePath + requestedSource; + // TODO: Need to check if the folder exists return path; } From ac1c5f20ecfb1e1809e6e113e7488cbc4175e2e7 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Tue, 16 Jul 2024 14:59:09 +0300 Subject: [PATCH 04/14] review fixes --- examples/main.cpp | 2 - openVulkanoCpp/Base/Utils.cpp | 18 ++++-- openVulkanoCpp/Shader/ShaderCompiler.cpp | 78 ++++++++---------------- openVulkanoCpp/Shader/ShaderCompiler.hpp | 16 +++-- openVulkanoCpp/Shader/test.vert | 8 +++ openVulkanoCpp/Shader/test1.glsl | 3 + 6 files changed, 59 insertions(+), 66 deletions(-) create mode 100644 openVulkanoCpp/Shader/test.vert create mode 100644 openVulkanoCpp/Shader/test1.glsl diff --git a/examples/main.cpp b/examples/main.cpp index c0a103b..18a8431 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -17,8 +17,6 @@ #include #include -#include "Shader/ShaderCompiler.hpp" - using namespace OpenVulkano; int main(int argc, char** argv) diff --git a/openVulkanoCpp/Base/Utils.cpp b/openVulkanoCpp/Base/Utils.cpp index a028fe6..cbdd6ed 100644 --- a/openVulkanoCpp/Base/Utils.cpp +++ b/openVulkanoCpp/Base/Utils.cpp @@ -7,9 +7,9 @@ #include "Utils.hpp" #ifdef _MSC_VER -#include + #include #else -#include + #include #endif #include #include @@ -57,7 +57,7 @@ namespace OpenVulkano #ifdef _MSC_VER return (uint64_t)::GetThreadId(::GetCurrentThread()); #else - return (uint64_t)pthread_self(); + return (uint64_t) pthread_self(); #endif } @@ -69,8 +69,16 @@ namespace OpenVulkano if (emptyOnMissing) return {}; throw std::runtime_error("Failed to open file '" + filePath + "'!"); } - size_t fileSize = static_cast(file.tellg()); - if (nullTerminateString) fileSize++; + const size_t fileSize = static_cast(file.tellg()); + if (nullTerminateString) + { + Array data(fileSize + 1); + file.seekg(0); + file.read(data.Data(), fileSize); + data[fileSize] = '\0'; + file.close(); + return data; + } Array data(fileSize); file.seekg(0); diff --git a/openVulkanoCpp/Shader/ShaderCompiler.cpp b/openVulkanoCpp/Shader/ShaderCompiler.cpp index 2f24c67..548986d 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.cpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.cpp @@ -1,5 +1,9 @@ #include "ShaderCompiler.hpp" +#include "Base/Logger.hpp" + +#include + namespace OpenVulkano { Unique ShaderCompiler::CompileGLSLToSpirv(const std::string& absPath, const std::string& incPath, @@ -8,11 +12,6 @@ namespace OpenVulkano { 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; @@ -25,8 +24,7 @@ namespace OpenVulkano if (preResult.GetCompilationStatus() != shaderc_compilation_status_success) { - throw std::runtime_error("Failed to preprocess shader: " + preResult.GetErrorMessage()); - return nullptr; + throw std::runtime_error("Failed preprocessing shader. Reason: " + preResult.GetErrorMessage()); } shaderc::CompilationResult result = @@ -34,68 +32,42 @@ namespace OpenVulkano if (result.GetCompilationStatus() != shaderc_compilation_status_success) { - throw std::runtime_error("Failed to compile shader: " + result.GetErrorMessage()); - return nullptr; + throw std::runtime_error("Failed compiling shader. Reason: " + result.GetErrorMessage()); } 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); - } + ShaderIncluder::ShaderIncluder(const std::string& path) : m_includePath(path) {} - shaderc_include_result* ShaderIncluder::GetInclude(const char* requested_source, shaderc_include_type type, - const char* requesting_source, uint64_t include_depth) + shaderc_include_result* ShaderIncluder::GetInclude(const char* requestedSource, shaderc_include_type type, + const char* requestingSource, uint64_t includeDepth) { - const char* includePath = GetActualPath(requested_source); - const char* content = RecordInclude(includePath); + IncludeData* includeData = new IncludeData(); + includeData->m_fullPath = ResolveInclude(requestedSource); + includeData->m_content = Utils::ReadFile(includeData->m_fullPath, false, false); // using nullTerminate as true causes crash in here. Needed to use as false. - 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; + shaderc_include_result* result = &includeData->result; + result->content = includeData->m_content.Data(); + result->content_length = includeData->m_content.Size(); + result->source_name = includeData->m_fullPath.data(); + result->source_name_length = includeData->m_fullPath.size(); + result->user_data = includeData; return result; } - void ShaderIncluder::ReleaseInclude(shaderc_include_result* data) { delete data; } - - std::string ShaderIncluder::ResolveInclude(const std::string requestedSource) + void ShaderIncluder::ReleaseInclude(shaderc_include_result* data) { - // Check if the file exists in the include paths - for (const std::string& includePath: m_includes) - { - std::string path = includePath + requestedSource; - // TODO: Need to check if the folder exists - return path; - } - - return ""; + delete static_cast(data->user_data); } - const char* ShaderIncluder::RecordInclude(const std::string& requestedSource) + std::string ShaderIncluder::ResolveInclude(const std::string& requestedSource) const { - 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; + // Check if the file exists in the include path + std::string path = m_includePath + requestedSource; + if (std::filesystem::exists(path)) return path; + else throw std::runtime_error("Failed to resolve include '" + requestedSource + "'!"); } } diff --git a/openVulkanoCpp/Shader/ShaderCompiler.hpp b/openVulkanoCpp/Shader/ShaderCompiler.hpp index b4d083d..6eb0df0 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.hpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.hpp @@ -11,21 +11,25 @@ namespace OpenVulkano { class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface { + struct IncludeData + { + shaderc_include_result result = {}; + std::string m_fullPath; + Array m_content; + }; 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; + shaderc_include_result* GetInclude(const char* requestedSource, shaderc_include_type type, + const char* requestingSource, uint64_t includeDepth) 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); + std::string ResolveInclude(const std::string& requestedSource) const; private: - std::vector m_includes; + std::string m_includePath; }; class ShaderCompiler diff --git a/openVulkanoCpp/Shader/test.vert b/openVulkanoCpp/Shader/test.vert new file mode 100644 index 0000000..3d16cda --- /dev/null +++ b/openVulkanoCpp/Shader/test.vert @@ -0,0 +1,8 @@ +#version 460 +#extension GL_KHR_vulkan_glsl : enable + +#include "test1.glsl" + +void main() +{ +}; \ No newline at end of file diff --git a/openVulkanoCpp/Shader/test1.glsl b/openVulkanoCpp/Shader/test1.glsl new file mode 100644 index 0000000..92671bc --- /dev/null +++ b/openVulkanoCpp/Shader/test1.glsl @@ -0,0 +1,3 @@ +void testfunction() +{ +}; \ No newline at end of file From dbd7b2dad54a4506070b86b76d4f79cab378a9f1 Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Tue, 16 Jul 2024 18:31:43 +0300 Subject: [PATCH 05/14] review refactors --- cmake/SetupVulkan.cmake | 15 ++--- openVulkanoCpp/Base/Utils.cpp | 13 +--- openVulkanoCpp/Shader/ShaderCompiler.cpp | 75 ++++++++++++++++++++---- openVulkanoCpp/Shader/ShaderCompiler.hpp | 36 +++--------- openVulkanoCpp/Shader/test.vert | 8 --- openVulkanoCpp/Shader/test1.glsl | 3 - 6 files changed, 79 insertions(+), 71 deletions(-) delete mode 100644 openVulkanoCpp/Shader/test.vert delete mode 100644 openVulkanoCpp/Shader/test1.glsl diff --git a/cmake/SetupVulkan.cmake b/cmake/SetupVulkan.cmake index b386f3a..24ed595 100644 --- a/cmake/SetupVulkan.cmake +++ b/cmake/SetupVulkan.cmake @@ -4,17 +4,12 @@ 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() + find_package(Vulkan OPTIONAL_COMPONENTS shaderc_combined) + if (Vulkan_shaderc_combined_FOUND) + target_link_libraries(${TARGET} PRIVATE Vulkan::shaderc_combined) + target_compile_definitions(${TARGET} PRIVATE HAS_SHADERC) + endif () endif () target_include_directories(${TARGET} PUBLIC ${Vulkan_INCLUDE_DIR}) diff --git a/openVulkanoCpp/Base/Utils.cpp b/openVulkanoCpp/Base/Utils.cpp index cbdd6ed..4987888 100644 --- a/openVulkanoCpp/Base/Utils.cpp +++ b/openVulkanoCpp/Base/Utils.cpp @@ -70,19 +70,10 @@ namespace OpenVulkano throw std::runtime_error("Failed to open file '" + filePath + "'!"); } const size_t fileSize = static_cast(file.tellg()); - if (nullTerminateString) - { - Array data(fileSize + 1); - file.seekg(0); - file.read(data.Data(), fileSize); - data[fileSize] = '\0'; - file.close(); - return data; - } - - Array data(fileSize); + Array data(fileSize + nullTerminateString); file.seekg(0); file.read(data.Data(), fileSize); + if (nullTerminateString) data[fileSize] = '\0'; file.close(); return data; } diff --git a/openVulkanoCpp/Shader/ShaderCompiler.cpp b/openVulkanoCpp/Shader/ShaderCompiler.cpp index 548986d..e8ccec7 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.cpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.cpp @@ -2,41 +2,93 @@ #include "Base/Logger.hpp" +#include #include namespace OpenVulkano { - Unique ShaderCompiler::CompileGLSLToSpirv(const std::string& absPath, const std::string& incPath, - const std::string& entryPoint, shaderc_shader_kind shaderStage, - bool bHaveIncludes) +#if defined(HAS_SHADERC) + class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface + { + struct IncludeData + { + shaderc_include_result result = {}; + std::string m_fullPath; + Array m_content; + }; + + public: + ShaderIncluder(const std::string& path); + ~ShaderIncluder() override = default; + + shaderc_include_result* GetInclude(const char* requestedSource, shaderc_include_type type, + const char* requestingSource, uint64_t includeDepth) override; + void ReleaseInclude(shaderc_include_result* data) override; + + private: + std::string ResolveInclude(const std::string& requestedSource) const; + + private: + std::string m_includePath; + }; + + shaderc_shader_kind CheckStage(const std::string& extensionName) + { + std::map stageMap = { + { "vert", shaderc_glsl_vertex_shader }, { "frag", shaderc_glsl_fragment_shader }, + { "comp", shaderc_glsl_compute_shader }, { "geom", shaderc_glsl_geometry_shader }, + { "tesc", shaderc_glsl_tess_control_shader }, { "tese", shaderc_glsl_tess_evaluation_shader }, + { "rgen", shaderc_glsl_raygen_shader }, { "rint", shaderc_glsl_intersection_shader }, + { "rahit", shaderc_glsl_anyhit_shader }, { "rchit", shaderc_glsl_closesthit_shader }, + { "rmiss", shaderc_glsl_miss_shader }, { "rcall", shaderc_glsl_callable_shader }, + { "task", shaderc_glsl_task_shader }, { "mesh", shaderc_glsl_mesh_shader } + }; + + auto it = stageMap.find(extensionName); + if (it != stageMap.end()) return it->second; + else throw std::runtime_error("Failed to find shader stage for extension '" + extensionName + "'!"); + } + + Array ShaderCompiler::CompileGLSLToSpirv(const std::string& absPath, bool hasIncludes, + const std::string& incPath, const std::string& entryPoint) { Array file = Utils::ReadFile(absPath, false, true); shaderc::Compiler shaderCompiler; shaderc::CompileOptions options; - if (bHaveIncludes) options.SetIncluder(std::make_unique(incPath)); + if (hasIncludes && incPath.size() > 0) { options.SetIncluder(std::make_unique(incPath)); } options.SetSourceLanguage(shaderc_source_language_glsl); options.SetSuppressWarnings(); + auto extensionSplit = Utils::SplitAtLastOccurrence(absPath, '.'); + shaderc::PreprocessedSourceCompilationResult preResult = - shaderCompiler.PreprocessGlsl(file.Data(), shaderStage, entryPoint.c_str(), options); + shaderCompiler.PreprocessGlsl(file.Data(), CheckStage(extensionSplit.second), entryPoint.c_str(), options); + + #if defined(_DEBUG) + std::string test = static_cast(preResult.begin(), preResult.end()); + // printf("Preprocessed shader: %s\n\n\n", test.c_str()); // Works fine + // Logger::APP->info("Preprocessed shader: {0}", test); gives error + #endif if (preResult.GetCompilationStatus() != shaderc_compilation_status_success) { throw std::runtime_error("Failed preprocessing shader. Reason: " + preResult.GetErrorMessage()); } - shaderc::CompilationResult result = - shaderCompiler.CompileGlslToSpv(static_cast(preResult.begin()), shaderStage, "", options); + shaderc::CompilationResult result = shaderCompiler.CompileGlslToSpv( + static_cast(preResult.begin()), CheckStage(extensionSplit.second), "", options); if (result.GetCompilationStatus() != shaderc_compilation_status_success) { throw std::runtime_error("Failed compiling shader. Reason: " + result.GetErrorMessage()); } - Unique spirv = std::make_unique((void*) result.begin()); - return spirv; + Array returnResult(result.cend() - result.cbegin()); + // Copy the data to the return array + std::copy(result.begin(), result.end(), returnResult.Data()); + return returnResult; } ShaderIncluder::ShaderIncluder(const std::string& path) : m_includePath(path) {} @@ -46,7 +98,9 @@ namespace OpenVulkano { IncludeData* includeData = new IncludeData(); includeData->m_fullPath = ResolveInclude(requestedSource); - includeData->m_content = Utils::ReadFile(includeData->m_fullPath, false, false); // using nullTerminate as true causes crash in here. Needed to use as false. + + // Do not null terminate the string + includeData->m_content = Utils::ReadFile(includeData->m_fullPath, false, false); shaderc_include_result* result = &includeData->result; result->content = includeData->m_content.Data(); @@ -70,4 +124,5 @@ namespace OpenVulkano if (std::filesystem::exists(path)) return path; else throw std::runtime_error("Failed to resolve include '" + requestedSource + "'!"); } +#endif } diff --git a/openVulkanoCpp/Shader/ShaderCompiler.hpp b/openVulkanoCpp/Shader/ShaderCompiler.hpp index 6eb0df0..ae3d561 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.hpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.hpp @@ -3,35 +3,10 @@ #include "Base/Utils.hpp" #include "Base/Wrapper.hpp" -#include -#include #include namespace OpenVulkano { - class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface - { - struct IncludeData - { - shaderc_include_result result = {}; - std::string m_fullPath; - Array m_content; - }; - public: - ShaderIncluder(const std::string& path); - ~ShaderIncluder() override = default; - - shaderc_include_result* GetInclude(const char* requestedSource, shaderc_include_type type, - const char* requestingSource, uint64_t includeDepth) override; - void ReleaseInclude(shaderc_include_result* data) override; - - private: - std::string ResolveInclude(const std::string& requestedSource) const; - - private: - std::string m_includePath; - }; - class ShaderCompiler { public: @@ -40,10 +15,13 @@ namespace OpenVulkano * @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); + static Array CompileGLSLToSpirv(const std::string& absPath, bool hasIncludes, + const std::string& incPath = std::string(), const std::string& entryPoint = "main") +#if defined(HAS_SHADERC) + ; +#else + { throw std::runtime_error("Shader compiler is not available on this platform"); } +#endif }; } \ No newline at end of file diff --git a/openVulkanoCpp/Shader/test.vert b/openVulkanoCpp/Shader/test.vert deleted file mode 100644 index 3d16cda..0000000 --- a/openVulkanoCpp/Shader/test.vert +++ /dev/null @@ -1,8 +0,0 @@ -#version 460 -#extension GL_KHR_vulkan_glsl : enable - -#include "test1.glsl" - -void main() -{ -}; \ No newline at end of file diff --git a/openVulkanoCpp/Shader/test1.glsl b/openVulkanoCpp/Shader/test1.glsl deleted file mode 100644 index 92671bc..0000000 --- a/openVulkanoCpp/Shader/test1.glsl +++ /dev/null @@ -1,3 +0,0 @@ -void testfunction() -{ -}; \ No newline at end of file From b572da31ac62fcf3962246a363b75cc1155fae55 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Tue, 16 Jul 2024 18:47:35 +0300 Subject: [PATCH 06/14] Image && ImageLoaderJpeg classes --- openVulkanoCpp/Image/Image.hpp | 28 +++++++++ openVulkanoCpp/Image/ImageLoader.hpp | 24 ++++++++ openVulkanoCpp/Image/ImageLoaderJpeg.cpp | 72 ++++++++++++++++++++++++ openVulkanoCpp/Image/ImageLoaderJpeg.hpp | 22 ++++++++ 4 files changed, 146 insertions(+) create mode 100644 openVulkanoCpp/Image/Image.hpp create mode 100644 openVulkanoCpp/Image/ImageLoader.hpp create mode 100644 openVulkanoCpp/Image/ImageLoaderJpeg.cpp create mode 100644 openVulkanoCpp/Image/ImageLoaderJpeg.hpp diff --git a/openVulkanoCpp/Image/Image.hpp b/openVulkanoCpp/Image/Image.hpp new file mode 100644 index 0000000..b440de3 --- /dev/null +++ b/openVulkanoCpp/Image/Image.hpp @@ -0,0 +1,28 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Data/Containers/Array.hpp" +#include "Math/Math.hpp" +#include "Scene/DataFormat.hpp" + +namespace OpenVulkano::Image +{ + enum class ImageFileType + { + JPEG, + PNG, + BMP, + }; + + struct Image + { + Math::Vector3ui resolution; + DataFormat dataFormat; + Array data; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/Image/ImageLoader.hpp b/openVulkanoCpp/Image/ImageLoader.hpp new file mode 100644 index 0000000..d3a288f --- /dev/null +++ b/openVulkanoCpp/Image/ImageLoader.hpp @@ -0,0 +1,24 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Image.hpp" +#include +#include +#include + +namespace OpenVulkano::Image +{ + class IImageLoader + { + public: + virtual ~IImageLoader() = default; + + virtual std::unique_ptr loadFromFile(const std::string& filePath) = 0; + virtual std::unique_ptr loadFromMemory(const std::vector& buffer) = 0; + }; +} \ No newline at end of file diff --git a/openVulkanoCpp/Image/ImageLoaderJpeg.cpp b/openVulkanoCpp/Image/ImageLoaderJpeg.cpp new file mode 100644 index 0000000..703fb24 --- /dev/null +++ b/openVulkanoCpp/Image/ImageLoaderJpeg.cpp @@ -0,0 +1,72 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "ImageLoaderJpeg.hpp" +#include +#include +#include + +#if __has_include("turbojpeg.h") + #include +#else + #define STB_IMAGE_IMPLEMENTATION + #include +#endif + +namespace OpenVulkano::Image +{ + std::unique_ptr ImageLoaderJpeg::loadFromFile(const std::string& filePath) + { + std::ifstream file(filePath, std::ios::binary); + if (!file) { throw std::runtime_error("Could not open file: " + filePath); } + std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + return loadJpeg(buffer.data(), buffer.size()); + } + + std::unique_ptr ImageLoaderJpeg::loadFromMemory(const std::vector& buffer) + { + return loadJpeg(buffer.data(), buffer.size()); + } + + std::unique_ptr ImageLoaderJpeg::loadJpeg(const uint8_t* data, size_t size) + { + Image result; + + int rows, cols; +#if __has_include("turbojpeg.h") + { + unsigned char* compressedImage = const_cast(data); + + int jpegSubsamp; + tjhandle jpegDecompressor = tjInitDecompress(); + tjDecompressHeader2(jpegDecompressor, compressedImage, size, &cols, &rows, &jpegSubsamp); + + const int channels = 4; + result.data = OpenVulkano::Array(cols * rows * channels); + result.dataFormat = OpenVulkano::DataFormat::R8G8B8A8_UINT; + + tjDecompress2(jpegDecompressor, compressedImage, size, result.data.Data(), cols, 0 /*pitch*/, rows, + TJPF_RGBA, TJFLAG_FASTDCT); + tjDestroy(jpegDecompressor); + } +#else + { + int channels; + uint8_t* pixelData = stbi_load_from_memory(data, size, &cols, &rows, &channels, 3); + result.data = OpenVulkano::Array(cols * rows * channels); + result.dataFormat = channels == 3 ? OpenVulkano::DataFormat::R8G8B8_UINT : + OpenVulkano::DataFormat::R8G8B8A8_UINT; + std::memcpy(result.data.Data(), pixelData, result.data.Size()); + stbi_image_free(pixelData); + } +#endif + result.resolution.x = cols; + result.resolution.y = rows; + result.resolution.z = 1; + + return std::make_unique(result); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Image/ImageLoaderJpeg.hpp b/openVulkanoCpp/Image/ImageLoaderJpeg.hpp new file mode 100644 index 0000000..5890ac9 --- /dev/null +++ b/openVulkanoCpp/Image/ImageLoaderJpeg.hpp @@ -0,0 +1,22 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "ImageLoader.hpp" + +namespace OpenVulkano::Image +{ + class ImageLoaderJpeg : public IImageLoader + { + public: + std::unique_ptr loadFromFile(const std::string& filePath) override; + std::unique_ptr loadFromMemory(const std::vector& buffer) override; + + private: + std::unique_ptr loadJpeg(const uint8_t* data, size_t size); + }; +} \ No newline at end of file From 91a81c1e9c0a2b659fb7f93373f92a16fea7f9c9 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Tue, 16 Jul 2024 21:40:24 +0300 Subject: [PATCH 07/14] Moving result struct instead of copying --- openVulkanoCpp/Image/ImageLoaderJpeg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openVulkanoCpp/Image/ImageLoaderJpeg.cpp b/openVulkanoCpp/Image/ImageLoaderJpeg.cpp index 703fb24..f9daec4 100644 --- a/openVulkanoCpp/Image/ImageLoaderJpeg.cpp +++ b/openVulkanoCpp/Image/ImageLoaderJpeg.cpp @@ -67,6 +67,6 @@ namespace OpenVulkano::Image result.resolution.y = rows; result.resolution.z = 1; - return std::make_unique(result); + return std::make_unique(std::move(result)); } } \ No newline at end of file From 7ea6fc8dc4ff1c04d59750801274c146ea06487f Mon Sep 17 00:00:00 2001 From: Metehan Tuncbilek Date: Tue, 16 Jul 2024 22:13:44 +0300 Subject: [PATCH 08/14] review fix done --- openVulkanoCpp/Shader/ShaderCompiler.cpp | 19 +++++++++++-------- openVulkanoCpp/Shader/ShaderCompiler.hpp | 2 -- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/openVulkanoCpp/Shader/ShaderCompiler.cpp b/openVulkanoCpp/Shader/ShaderCompiler.cpp index e8ccec7..e70a3f2 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.cpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.cpp @@ -1,13 +1,16 @@ +#if defined(HAS_SHADERC) + #include "ShaderCompiler.hpp" #include "Base/Logger.hpp" +#include #include #include namespace OpenVulkano { -#if defined(HAS_SHADERC) + class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface { struct IncludeData @@ -34,7 +37,7 @@ namespace OpenVulkano shaderc_shader_kind CheckStage(const std::string& extensionName) { - std::map stageMap = { + static std::map stageMap = { { "vert", shaderc_glsl_vertex_shader }, { "frag", shaderc_glsl_fragment_shader }, { "comp", shaderc_glsl_compute_shader }, { "geom", shaderc_glsl_geometry_shader }, { "tesc", shaderc_glsl_tess_control_shader }, { "tese", shaderc_glsl_tess_evaluation_shader }, @@ -50,7 +53,7 @@ namespace OpenVulkano } Array ShaderCompiler::CompileGLSLToSpirv(const std::string& absPath, bool hasIncludes, - const std::string& incPath, const std::string& entryPoint) + const std::string& incPath, const std::string& entryPoint) { Array file = Utils::ReadFile(absPath, false, true); @@ -66,11 +69,11 @@ namespace OpenVulkano shaderc::PreprocessedSourceCompilationResult preResult = shaderCompiler.PreprocessGlsl(file.Data(), CheckStage(extensionSplit.second), entryPoint.c_str(), options); - #if defined(_DEBUG) + #if defined(_DEBUG) std::string test = static_cast(preResult.begin(), preResult.end()); - // printf("Preprocessed shader: %s\n\n\n", test.c_str()); // Works fine - // Logger::APP->info("Preprocessed shader: {0}", test); gives error - #endif + // printf("Preprocessed shader: %s\n\n\n", test.c_str()); // Works fine + // Logger::APP->info("Preprocessed shader: {0}", test); gives error + #endif if (preResult.GetCompilationStatus() != shaderc_compilation_status_success) { @@ -124,5 +127,5 @@ namespace OpenVulkano if (std::filesystem::exists(path)) return path; else throw std::runtime_error("Failed to resolve include '" + requestedSource + "'!"); } -#endif } +#endif diff --git a/openVulkanoCpp/Shader/ShaderCompiler.hpp b/openVulkanoCpp/Shader/ShaderCompiler.hpp index ae3d561..4f42997 100644 --- a/openVulkanoCpp/Shader/ShaderCompiler.hpp +++ b/openVulkanoCpp/Shader/ShaderCompiler.hpp @@ -3,8 +3,6 @@ #include "Base/Utils.hpp" #include "Base/Wrapper.hpp" -#include - namespace OpenVulkano { class ShaderCompiler From 28f48377d50e2635864c08296ce6f90e10bba9e1 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Tue, 16 Jul 2024 13:31:21 +0300 Subject: [PATCH 09/14] include shader files in Visual Studio solution --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5039b4b..9cf720b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,8 +48,15 @@ if(IOS) add_executable(openVulkanoCpp examples/main.m ${resources}) else() file(GLOB_RECURSE sources CONFIGURE_DEPENDS "openVulkanoCpp/*.h" "openVulkanoCpp/*.c" "openVulkanoCpp/*.hpp" "openVulkanoCpp/*.cpp" "examples/*.hpp" "examples/*.cpp") - add_executable(openVulkanoCpp examples/main.cpp) + file(GLOB SHADER_SRC_FILES ${ROOT_FOLDER}/openVulkanoCpp/Shader/*) + list(FILTER SHADER_SRC_FILES EXCLUDE REGEX ".*\\.(hpp|cpp)$") + add_executable(openVulkanoCpp examples/main.cpp ${SHADER_SRC_FILES}) + if (MSVC) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) + source_group("Shaders" FILES ${SHADER_SRC_FILES}) + endif() endif() + FilterPlatformPaths(sources) SetWarningSettings(openVulkanoCpp) set_property(TARGET openVulkanoCpp PROPERTY CXX_STANDARD 20) From 5e7cf1ba907b12e46bab300fbf9015c9b716867f Mon Sep 17 00:00:00 2001 From: ohyzha Date: Tue, 16 Jul 2024 13:32:08 +0300 Subject: [PATCH 10/14] fix broken key bindings --- openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp | 2 +- openVulkanoCpp/Input/InputManager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp b/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp index eadc109..320fdfb 100644 --- a/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp +++ b/openVulkanoCpp/Host/GLFW/InputMappingGLFW.hpp @@ -48,7 +48,7 @@ namespace OpenVulkano::GLFW { remappedKey = i - 320; } - else if (i >= GLFW_KEY_NUM_LOCK) + else if (i == GLFW_KEY_NUM_LOCK) { remappedKey = 17; } diff --git a/openVulkanoCpp/Input/InputManager.cpp b/openVulkanoCpp/Input/InputManager.cpp index b17ca6a..5e36010 100644 --- a/openVulkanoCpp/Input/InputManager.cpp +++ b/openVulkanoCpp/Input/InputManager.cpp @@ -69,7 +69,7 @@ namespace OpenVulkano::Input for (const KeyBinding binding : action->GetKeys()) { if (binding.key.GetInputDeviceType() != device->GetType()) continue; - if (device->GetButton(binding.key)) return true; + return device->GetButton(binding.key); } } return false; @@ -80,7 +80,7 @@ namespace OpenVulkano::Input for(const InputDevice* device : devices) { if (key.GetInputDeviceType() != device->GetType()) continue; - if (device->GetButton(key)) return true; + return device->GetButton(key); } return false; } From 60c139b5baf07dcbddbd45b19c425bb8f0eb971e Mon Sep 17 00:00:00 2001 From: ohyzha Date: Thu, 18 Jul 2024 14:45:59 +0300 Subject: [PATCH 11/14] fix rendering pipeline when drawable has no indices --- openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp index c96932b..1392fea 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanGeometry.hpp @@ -52,7 +52,8 @@ namespace OpenVulkano::Vulkan void RecordDraw(vk::CommandBuffer& cmdBuffer) { - cmdBuffer.drawIndexed(m_geometry->GetIndexCount(), 1, 0, 0, 0); + if (m_geometry->GetIndexCount()) { cmdBuffer.drawIndexed(m_geometry->GetIndexCount(), 1, 0, 0, 0); } + else { cmdBuffer.draw(m_geometry->GetVertexCount(), 1, 0, 0); } } void Close() override From 5023fe64ce82a3204f164e01efab292f705461b6 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Thu, 18 Jul 2024 14:47:34 +0300 Subject: [PATCH 12/14] fix flipped camera movements --- openVulkanoCpp/Scene/Camera.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openVulkanoCpp/Scene/Camera.hpp b/openVulkanoCpp/Scene/Camera.hpp index 478176b..af6696c 100644 --- a/openVulkanoCpp/Scene/Camera.hpp +++ b/openVulkanoCpp/Scene/Camera.hpp @@ -99,7 +99,7 @@ namespace OpenVulkano::Scene { //TODO this should be done based on the clipspace used by the rendering api // In vulkan the screen space is defined as y=0=top and y=1=bottom and thus the coordinate have to be flipped - m_viewProjection = m_projection * Math::Matrix4f(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) * m_view; + m_viewProjection = m_projection * m_view; } void UpdateWorldMatrix(const Math::Matrix4f& parentWorldMat) override @@ -252,6 +252,7 @@ namespace OpenVulkano::Scene void UpdateProjectionMatrix() override { m_projection = Math::Utils::perspectiveRH_ZO(m_fov, m_aspect, m_nearPlane, m_farPlane); + m_projection *= Math::Matrix4f(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); UpdateViewProjectionMatrix(); } From cfb8b76801468a24569e9e2df0af1027ab99e705 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Thu, 18 Jul 2024 14:48:50 +0300 Subject: [PATCH 13/14] implement billboard shader and add new example --- examples/ExampleApps/BillboardExampleApp.cpp | 168 ++++++++++++++++++ examples/ExampleApps/BillboardExampleApp.hpp | 27 +++ examples/main.cpp | 3 + openVulkanoCpp/Base/IGraphicsAppManager.hpp | 1 + .../Controller/FreeCamCameraController.cpp | 3 +- .../Controller/FreeCamCameraController.hpp | 2 +- openVulkanoCpp/Host/GraphicsAppManager.hpp | 2 + openVulkanoCpp/Scene/SimpleDrawable.cpp | 8 +- openVulkanoCpp/Scene/SimpleDrawable.hpp | 16 +- openVulkanoCpp/Shader/billboard.frag | 9 + openVulkanoCpp/Shader/billboard.vert | 55 ++++++ .../Shader/billboardFromSinglePoint.geom | 75 ++++++++ .../Shader/billboardFromSinglePoint.vert | 35 ++++ .../Scene/SimpleDrawableVulkanEncoder.cpp | 14 ++ 14 files changed, 406 insertions(+), 12 deletions(-) create mode 100644 examples/ExampleApps/BillboardExampleApp.cpp create mode 100644 examples/ExampleApps/BillboardExampleApp.hpp create mode 100644 openVulkanoCpp/Shader/billboard.frag create mode 100644 openVulkanoCpp/Shader/billboard.vert create mode 100644 openVulkanoCpp/Shader/billboardFromSinglePoint.geom create mode 100644 openVulkanoCpp/Shader/billboardFromSinglePoint.vert diff --git a/examples/ExampleApps/BillboardExampleApp.cpp b/examples/ExampleApps/BillboardExampleApp.cpp new file mode 100644 index 0000000..9c0da10 --- /dev/null +++ b/examples/ExampleApps/BillboardExampleApp.cpp @@ -0,0 +1,168 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "BillboardExampleApp.hpp" +#include "Scene/Scene.hpp" +#include "Scene/Shader/Shader.hpp" +#include "Scene/Geometry.hpp" +#include "Scene/GeometryFactory.hpp" +#include "Scene/Material.hpp" +#include "Scene/Vertex.hpp" +#include "Scene/SimpleDrawable.hpp" +#include "Scene/UI/PerformanceInfo.hpp" +#include "Scene/UniformBuffer.hpp" +#include "Input/InputManager.hpp" +#include "Host/GraphicsAppManager.hpp" +#include "Host/GLFW/WindowGLFW.hpp" +#include "Math/Math.hpp" +#include "Base/EngineConfiguration.hpp" +#include "Controller/FreeCamCameraController.hpp" + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "cert-msc50-cpp" +#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" + + +namespace OpenVulkano +{ + using namespace Scene; + using namespace Input; + using namespace Math; + + class BillboardExampleAppImpl final : public BillboardExampleApp + { + public: + + struct BillboardControlBlock + { + glm::vec2 quadSize; + glm::vec2 windowSize; + bool isFixedSize; + }; + + void Init() override + { + auto engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); + engineConfig->SetNumThreads(4); + engineConfig->SetPreferFramebufferFormatSRGB(false); + + std::srand(1); // Fix seed for random numbers + m_scene.Init(); + m_cam.Init(70, 16, 9, 0.1f, 100); + m_scene.SetCamera(&m_cam); + + m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboardFromSinglePoint"); + m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::GEOMETRY, "Shader/billboardFromSinglePoint"); + m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/billboard"); + m_quadBillboardShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); + m_quadBillboardShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); + m_quadBillboardShader.topology = Topology::POINT_LIST; + + m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboard"); + m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/billboard"); + m_shader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); + m_shader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); + m_shader.cullMode = CullMode::NONE; + + constexpr int quadsCnt = 7; + constexpr int otherCnt = 2; + constexpr int cntDrawables = quadsCnt + otherCnt; + + m_bbContolBlock.quadSize = { 100.f, 100.f }; + m_bbContolBlock.windowSize = { 0, 0 }; // will be initialized on first frame + m_bbContolBlock.isFixedSize = false; + m_uniBuffer.Init(sizeof(BillboardControlBlock), &m_bbContolBlock); + m_drawablesPool.resize(cntDrawables); + m_nodesPool.resize(cntDrawables); + m_geo.reserve(cntDrawables); + + for (uint32_t i = 0; i < cntDrawables; i++) + { + Geometry* geo = nullptr; + m_nodesPool[i].Init(); + if (i < quadsCnt) + { + geo = new Geometry(); + geo->Init(1, 0); + geo->vertices[0].position = glm::vec3(1 + i, i, 0); + geo->vertices[0].color = glm::vec4(1, 0, 0, 1); + m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, std::rand() % 5))); + m_drawablesPool[i].Init(&m_quadBillboardShader, geo, &m_mat, &m_uniBuffer); + } + else + { + geo = GeometryFactory::MakePyramid(1, 1, glm::vec4(0, 1, 0, 1)); + m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, -std::rand() % 10))); + m_drawablesPool[i].Init(&m_shader, geo, &m_mat, &m_uniBuffer); + } + m_geo.push_back(geo); + m_scene.GetRoot()->AddChild(&m_nodesPool[i]); + m_nodesPool[i].AddDrawable(&m_drawablesPool[i]); + m_nodesPool[i].SetUpdateFrequency(UpdateFrequency::Always); + } + + GetGraphicsAppManager()->GetRenderer()->SetScene(&m_scene); + + m_camController.Init(&m_cam); + m_camController.SetDefaultKeybindings(); + m_camController.SetPosition({ 0, 0, 5 }); + m_camController.SetBoostFactor(5); + + std::shared_ptr m_perfInfo = + std::make_shared(); + m_ui.AddElement(m_perfInfo); + GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui); + } + + void Tick() override + { + static bool firstFrame = true; + if (firstFrame) + { + glm::vec2 sz = GetGraphicsAppManager()->GetWindow()->GetSize(); + m_bbContolBlock.windowSize = sz; + m_uniBuffer.updated = true; + firstFrame = false; + } + m_camController.Tick(); + } + + void Close() override + { + for (Geometry* g: m_geo) + { + delete g; + } + } + + private: + OpenVulkano::Scene::Scene m_scene; + BillboardControlBlock m_bbContolBlock; + PerspectiveCamera m_cam; + UniformBuffer m_uniBuffer; + OpenVulkano::FreeCamCameraController m_camController; + Material m_mat; + Shader m_shader; + Shader m_quadBillboardShader; + std::vector m_drawablesPool; + std::vector m_nodesPool; + Vector3f_SIMD m_position = { 0, 0, -10 }; + OpenVulkano::Scene::UI::SimpleUi m_ui; + std::vector m_geo; + std::shared_ptr m_perfInfo; + }; + + IGraphicsApp* BillboardExampleApp::Create() { return new BillboardExampleAppImpl(); } + + std::unique_ptr BillboardExampleApp::CreateUnique() + { + return std::make_unique(); + } + +} + +#pragma clang diagnostic pop +#pragma clang diagnostic pop \ No newline at end of file diff --git a/examples/ExampleApps/BillboardExampleApp.hpp b/examples/ExampleApps/BillboardExampleApp.hpp new file mode 100644 index 0000000..fa1c215 --- /dev/null +++ b/examples/ExampleApps/BillboardExampleApp.hpp @@ -0,0 +1,27 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Base/IGraphicsApp.hpp" +#include + +namespace OpenVulkano +{ + class BillboardExampleApp : public IGraphicsApp + { + public: + static IGraphicsApp* Create(); + + static std::unique_ptr CreateUnique(); + + [[nodiscard]] std::string GetAppName() const final + { return "Billboard ExampleApp"; } + + [[nodiscard]] OpenVulkano::Version GetAppVersion() const final + { return {"v1.0"}; } + }; +} \ No newline at end of file diff --git a/examples/main.cpp b/examples/main.cpp index 18a8431..388087e 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -8,6 +8,7 @@ #include "ExampleApps/CubesExampleApp.hpp" #include "ExampleApps/MovingCubeApp.hpp" #include "ExampleApps/TexturedCubeExampleApp.hpp" +#include "ExampleApps/BillboardExampleApp.hpp" #include #include @@ -25,6 +26,7 @@ int main(int argc, char** argv) "Cubes Example App", "Moving Cube Example App", "Textured Cube Example App", + "Billboard Example App" }; int selectedExample = 0; @@ -41,6 +43,7 @@ int main(int argc, char** argv) case 0: app = CubesExampleApp::CreateUnique(); break; case 1: app = MovingCubeApp::CreateUnique(); break; case 2: app = TexturedCubeExampleApp::CreateUnique(); break; + case 3: app = BillboardExampleApp::CreateUnique(); break; default: throw std::runtime_error("Invalid menu selection!"); break; } diff --git a/openVulkanoCpp/Base/IGraphicsAppManager.hpp b/openVulkanoCpp/Base/IGraphicsAppManager.hpp index 536c6b5..14cf156 100644 --- a/openVulkanoCpp/Base/IGraphicsAppManager.hpp +++ b/openVulkanoCpp/Base/IGraphicsAppManager.hpp @@ -16,6 +16,7 @@ namespace OpenVulkano virtual RenderAPI::RenderApi GetRenderApi() const = 0; virtual IGraphicsApp* GetGraphicsApp() const = 0; virtual IRenderer* GetRenderer() const = 0; + virtual IWindow* GetWindow() const = 0; virtual bool IsRunning() const = 0; virtual bool IsPaused() const = 0; virtual void Stop() = 0; diff --git a/openVulkanoCpp/Controller/FreeCamCameraController.cpp b/openVulkanoCpp/Controller/FreeCamCameraController.cpp index 89342a1..393514f 100644 --- a/openVulkanoCpp/Controller/FreeCamCameraController.cpp +++ b/openVulkanoCpp/Controller/FreeCamCameraController.cpp @@ -32,8 +32,7 @@ namespace OpenVulkano vec = Math::Utils::normalize(vec); } - float timeScale = CURRENT_FRAME.frameTime; //TODO - + float timeScale = 5 * CURRENT_FRAME.frameTime; //TODO vec = vec * timeScale * 3.0f; // scale vector if (input->GetButton(m_actionBoost)) { diff --git a/openVulkanoCpp/Controller/FreeCamCameraController.hpp b/openVulkanoCpp/Controller/FreeCamCameraController.hpp index ef163c1..2fc33ba 100644 --- a/openVulkanoCpp/Controller/FreeCamCameraController.hpp +++ b/openVulkanoCpp/Controller/FreeCamCameraController.hpp @@ -18,7 +18,7 @@ namespace OpenVulkano class FreeCamCameraController final : public CameraController { - float m_yaw = 0, m_pitch = 0, m_boostFactor = 2; + float m_yaw = 0, m_pitch = 0, m_boostFactor = 1.5; Math::Vector3f_SIMD m_position = { 0, 0, 0 }; Input::InputAction* m_actionForward; diff --git a/openVulkanoCpp/Host/GraphicsAppManager.hpp b/openVulkanoCpp/Host/GraphicsAppManager.hpp index 9e53818..5d4b627 100644 --- a/openVulkanoCpp/Host/GraphicsAppManager.hpp +++ b/openVulkanoCpp/Host/GraphicsAppManager.hpp @@ -50,6 +50,8 @@ namespace OpenVulkano [[nodiscard]] IRenderer* GetRenderer() const override { return renderer.get(); } + [[nodiscard]] IWindow* GetWindow() const override { return window; } + [[nodiscard]] bool IsRunning() const override { return running; } [[nodiscard]] bool IsPaused() const override { return paused; } diff --git a/openVulkanoCpp/Scene/SimpleDrawable.cpp b/openVulkanoCpp/Scene/SimpleDrawable.cpp index 7bc3fac..0920971 100644 --- a/openVulkanoCpp/Scene/SimpleDrawable.cpp +++ b/openVulkanoCpp/Scene/SimpleDrawable.cpp @@ -9,19 +9,21 @@ namespace OpenVulkano::Scene { - void SimpleDrawable::Init(Shader* shader, Geometry* mesh, Material* material) + void SimpleDrawable::Init(Shader* shader, Geometry* mesh, Material* material, UniformBuffer* uniBuffer) { - if (m_mesh || m_material) throw std::runtime_error("Drawable is already initialized."); + if (m_mesh || m_material || m_uniBuffer) throw std::runtime_error("Drawable is already initialized."); m_mesh = mesh; m_material = material; + m_uniBuffer = uniBuffer; SetShader(shader); } void SimpleDrawable::Init(SimpleDrawable* drawable) { - if (m_mesh || m_material) throw std::runtime_error("Drawable is already initialized."); + if (m_mesh || m_material || m_uniBuffer) throw std::runtime_error("Drawable is already initialized."); m_mesh = drawable->m_mesh; m_material = drawable->m_material; + m_uniBuffer = drawable->m_uniBuffer; SetShader(drawable->GetShader()); } } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/SimpleDrawable.hpp b/openVulkanoCpp/Scene/SimpleDrawable.hpp index 49908d2..0f5aa13 100644 --- a/openVulkanoCpp/Scene/SimpleDrawable.hpp +++ b/openVulkanoCpp/Scene/SimpleDrawable.hpp @@ -12,20 +12,22 @@ namespace OpenVulkano::Scene { class Geometry; class Material; + class UniformBuffer; class SimpleDrawable final : public Drawable { Geometry* m_mesh = nullptr; Material* m_material = nullptr; + UniformBuffer* m_uniBuffer = nullptr; public: - SimpleDrawable() : Drawable(DrawEncoder::GetDrawEncoder()) - {} + SimpleDrawable() : Drawable(DrawEncoder::GetDrawEncoder()) {} explicit SimpleDrawable(const SimpleDrawable* toCopy) - : Drawable(DrawEncoder::GetDrawEncoder()) - , m_mesh(toCopy->m_mesh) - , m_material(toCopy->m_material) + : Drawable(DrawEncoder::GetDrawEncoder()) + , m_mesh(toCopy->m_mesh) + , m_material(toCopy->m_material) + , m_uniBuffer(toCopy->m_uniBuffer) { SetShader(toCopy->GetShader()); } @@ -35,12 +37,14 @@ namespace OpenVulkano::Scene //if (m_mesh) SimpleDrawable::Close(); } - void Init(Shader* shader, Geometry* mesh, Material* material); + void Init(Shader* shader, Geometry* mesh, Material* material, UniformBuffer* uniBuffer = nullptr); void Init(SimpleDrawable* drawable); [[nodiscard]] Geometry* GetMesh() const { return m_mesh; } [[nodiscard]] Material* GetMaterial() const { return m_material; } + + [[nodiscard]] UniformBuffer* GetBuffer() const { return m_uniBuffer; } }; } diff --git a/openVulkanoCpp/Shader/billboard.frag b/openVulkanoCpp/Shader/billboard.frag new file mode 100644 index 0000000..1a0e2cd --- /dev/null +++ b/openVulkanoCpp/Shader/billboard.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec4 color; +layout(location = 0) out vec4 outColor; + +void main() +{ + outColor = color; +} \ No newline at end of file diff --git a/openVulkanoCpp/Shader/billboard.vert b/openVulkanoCpp/Shader/billboard.vert new file mode 100644 index 0000000..74787e8 --- /dev/null +++ b/openVulkanoCpp/Shader/billboard.vert @@ -0,0 +1,55 @@ +#version 450 + +layout(location = 0) in vec3 pos; +layout(location = 1) in vec3 normal; +layout(location = 5) in vec4 color; +layout(location = 0) out vec4 outColor; + +layout(set = 0, binding = 0) uniform NodeData +{ + mat4 world; +} node; + +layout(set = 1, binding = 0) uniform CameraData +{ + mat4 viewProjection; + mat4 view; + mat4 projection; + vec4 camPos; +} cam; + +layout(set = 2, binding = 0) uniform BillboardData +{ + vec2 size; + vec2 windowSize; + bool isFixedSize; +} billboardInfo; + +void main() { + if (!billboardInfo.isFixedSize) + { + mat4 mv = cam.view * node.world; + + mv[0][0] = 1; + mv[0][1] = 0; + mv[0][2] = 0; + + mv[1][0] = 0; + mv[1][1] = 1; + mv[1][2] = 0; + + mv[2][0] = 0; + mv[2][1] = 0; + mv[2][2] = 1; + + gl_Position = cam.projection * mv * vec4(pos, 1); + } + else + { + vec4 billboardPos = vec4(0, 0, 0, 1); + vec4 viewPos = cam.view * node.world * billboardPos; + float dist = -viewPos.z; + gl_Position = cam.projection * (viewPos + vec4(pos.xy*dist*0.2,0,0)); + } + outColor = color; +} diff --git a/openVulkanoCpp/Shader/billboardFromSinglePoint.geom b/openVulkanoCpp/Shader/billboardFromSinglePoint.geom new file mode 100644 index 0000000..5c3d2cf --- /dev/null +++ b/openVulkanoCpp/Shader/billboardFromSinglePoint.geom @@ -0,0 +1,75 @@ +#version 450 + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +layout(set = 0, binding = 0) uniform NodeData +{ + mat4 world; +} node; + +layout(set = 1, binding = 0) uniform CameraData +{ + mat4 viewProjection; + mat4 view; + mat4 projection; + vec4 camPos; +} cam; + +layout(set = 2, binding = 0) uniform BillboardData +{ + vec2 size; + vec2 windowSize; + bool isFixedSize; +} billboardInfo; + +layout(location = 0) out vec4 color; + +layout(location = 0) in VS_OUT { + vec4 color; +} gs_in[]; + +void main() { + // The desired point for the billboard + vec3 pos = gl_in[0].gl_Position.xyz; + + if(!billboardInfo.isFixedSize) + { + vec3 cameraRight = normalize(vec3(cam.view[0][0], cam.view[1][0], cam.view[2][0])); + vec3 cameraUp = normalize(vec3(cam.view[0][1], cam.view[1][1], cam.view[2][1])); + const vec2 offsets[4] = { + vec2(0.5, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, -0.5), + vec2(-0.5, 0.5) + }; + + for (int i = 0; i < 4; i++) + { + vec2 scaledSize = billboardInfo.size / length(billboardInfo.size); + gl_Position = cam.viewProjection * vec4(pos + cameraRight * offsets[i].x * scaledSize.x + cameraUp * offsets[i].y * scaledSize.y, 1.0); + color = gs_in[0].color; + EmitVertex(); + } + EndPrimitive(); + } + else + { + const vec2 offsets[4] = { + vec2(-0.5, -0.5), + vec2(-0.5, 0.5), + vec2(0.5, -0.5), + vec2(0.5, 0.5) + }; + + for (int i = 0; i < 4; i++) + { + gl_Position = cam.viewProjection * vec4(pos, 1); + gl_Position /= gl_Position.w; + gl_Position.xy += offsets[i] * vec2(billboardInfo.size.x/billboardInfo.windowSize.x, billboardInfo.size.x/billboardInfo.windowSize.y); + color = gs_in[0].color; + EmitVertex(); + } + EndPrimitive(); + } +} diff --git a/openVulkanoCpp/Shader/billboardFromSinglePoint.vert b/openVulkanoCpp/Shader/billboardFromSinglePoint.vert new file mode 100644 index 0000000..3ad4110 --- /dev/null +++ b/openVulkanoCpp/Shader/billboardFromSinglePoint.vert @@ -0,0 +1,35 @@ +#version 450 + +layout(location = 0) in vec3 pos; +layout(location = 1) in vec3 normal; +layout(location = 5) in vec4 color; + +layout(location = 0) out VS_OUT { + vec4 color; +} vs_out; + +layout(set = 0, binding = 0) uniform NodeData +{ + mat4 world; +} node; + +layout(set = 1, binding = 0) uniform CameraData +{ + mat4 viewProjection; + mat4 view; + mat4 projection; + vec4 camPos; +} cam; + +layout(set = 2, binding = 0) uniform BillboardData +{ + vec2 size; + vec2 windowSize; + bool isFixedSize; +} billboardInfo; + +void main() { + // single point + gl_Position = node.world * vec4(pos, 1); + vs_out.color = color; +} diff --git a/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp b/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp index b38ea11..54ba990 100644 --- a/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp +++ b/openVulkanoCpp/Vulkan/Scene/SimpleDrawableVulkanEncoder.cpp @@ -6,9 +6,11 @@ #include "Scene/SimpleDrawable.hpp" #include "Scene/Material.hpp" +#include "Scene/UniformBuffer.hpp" #include "VulkanGeometry.hpp" #include "VulkanNode.hpp" #include "Vulkan/VulkanDrawContext.hpp" +#include "Vulkan/Scene/VulkanUniformBuffer.hpp" #include "VulkanTexture.hpp" using namespace OpenVulkano::Scene; @@ -22,6 +24,18 @@ namespace OpenVulkano::Vulkan VulkanGeometry* renderGeo = static_cast(mesh->renderGeo); if (!renderGeo) renderGeo = drawContext->renderer->GetResourceManager().PrepareGeometry(mesh); renderGeo->RecordBind(drawContext->commandBuffer); + + if (drawable->GetBuffer()) + { + + VulkanUniformBuffer* vkBuffer = static_cast(drawable->GetBuffer()->renderBuffer); + if (!vkBuffer) + { + vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(drawable->GetBuffer()); + } + vkBuffer->Record(drawContext); + } + if (Material* material = drawable->GetMaterial()) { if (Texture* texture = material->texture) From a28b4ab53c8aa4587b512db1d4096e38191a1d9d Mon Sep 17 00:00:00 2001 From: ohyzha Date: Fri, 19 Jul 2024 10:17:45 +0300 Subject: [PATCH 14/14] fixes --- examples/ExampleApps/BillboardExampleApp.cpp | 34 +++++++----------- openVulkanoCpp/Scene/UniformBuffer.hpp | 5 +-- openVulkanoCpp/Shader/basicTexture.frag | 1 + openVulkanoCpp/Shader/billboard.frag | 9 ----- openVulkanoCpp/Shader/billboard.vert | 17 +++++---- .../Shader/billboardFromSinglePoint.geom | 35 +++++++++++++++---- .../Shader/billboardFromSinglePoint.vert | 18 ++-------- 7 files changed, 57 insertions(+), 62 deletions(-) delete mode 100644 openVulkanoCpp/Shader/billboard.frag diff --git a/examples/ExampleApps/BillboardExampleApp.cpp b/examples/ExampleApps/BillboardExampleApp.cpp index 9c0da10..b579a17 100644 --- a/examples/ExampleApps/BillboardExampleApp.cpp +++ b/examples/ExampleApps/BillboardExampleApp.cpp @@ -21,11 +21,6 @@ #include "Base/EngineConfiguration.hpp" #include "Controller/FreeCamCameraController.hpp" -#pragma clang diagnostic push -#pragma ide diagnostic ignored "cert-msc50-cpp" -#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" - - namespace OpenVulkano { using namespace Scene; @@ -38,8 +33,7 @@ namespace OpenVulkano struct BillboardControlBlock { - glm::vec2 quadSize; - glm::vec2 windowSize; + Math::Vector2f quadSize; bool isFixedSize; }; @@ -56,14 +50,16 @@ namespace OpenVulkano m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboardFromSinglePoint"); m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::GEOMETRY, "Shader/billboardFromSinglePoint"); - m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/billboard"); + m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basicTexture"); m_quadBillboardShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); + m_quadBillboardShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); m_quadBillboardShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); m_quadBillboardShader.topology = Topology::POINT_LIST; m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboard"); - m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/billboard"); + m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basic"); m_shader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); + m_shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); m_shader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); m_shader.cullMode = CullMode::NONE; @@ -72,12 +68,13 @@ namespace OpenVulkano constexpr int cntDrawables = quadsCnt + otherCnt; m_bbContolBlock.quadSize = { 100.f, 100.f }; - m_bbContolBlock.windowSize = { 0, 0 }; // will be initialized on first frame m_bbContolBlock.isFixedSize = false; m_uniBuffer.Init(sizeof(BillboardControlBlock), &m_bbContolBlock); + m_uniBuffer.setId = 3; m_drawablesPool.resize(cntDrawables); m_nodesPool.resize(cntDrawables); m_geo.reserve(cntDrawables); + m_texturedMat.texture = &Texture::PLACEHOLDER; for (uint32_t i = 0; i < cntDrawables; i++) { @@ -88,9 +85,12 @@ namespace OpenVulkano geo = new Geometry(); geo->Init(1, 0); geo->vertices[0].position = glm::vec3(1 + i, i, 0); - geo->vertices[0].color = glm::vec4(1, 0, 0, 1); + if (i >= 1 && i <= 3) + geo->vertices[0].color = glm::vec4(1, 1, 1, 1); + else + geo->vertices[0].color = glm::vec4(1, 0, 0, 1); m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, std::rand() % 5))); - m_drawablesPool[i].Init(&m_quadBillboardShader, geo, &m_mat, &m_uniBuffer); + m_drawablesPool[i].Init(&m_quadBillboardShader, geo, &m_texturedMat, &m_uniBuffer); } else { @@ -101,7 +101,6 @@ namespace OpenVulkano m_geo.push_back(geo); m_scene.GetRoot()->AddChild(&m_nodesPool[i]); m_nodesPool[i].AddDrawable(&m_drawablesPool[i]); - m_nodesPool[i].SetUpdateFrequency(UpdateFrequency::Always); } GetGraphicsAppManager()->GetRenderer()->SetScene(&m_scene); @@ -119,14 +118,6 @@ namespace OpenVulkano void Tick() override { - static bool firstFrame = true; - if (firstFrame) - { - glm::vec2 sz = GetGraphicsAppManager()->GetWindow()->GetSize(); - m_bbContolBlock.windowSize = sz; - m_uniBuffer.updated = true; - firstFrame = false; - } m_camController.Tick(); } @@ -145,6 +136,7 @@ namespace OpenVulkano UniformBuffer m_uniBuffer; OpenVulkano::FreeCamCameraController m_camController; Material m_mat; + Material m_texturedMat; Shader m_shader; Shader m_quadBillboardShader; std::vector m_drawablesPool; diff --git a/openVulkanoCpp/Scene/UniformBuffer.hpp b/openVulkanoCpp/Scene/UniformBuffer.hpp index 06cf9ef..1551d3f 100644 --- a/openVulkanoCpp/Scene/UniformBuffer.hpp +++ b/openVulkanoCpp/Scene/UniformBuffer.hpp @@ -16,18 +16,19 @@ namespace OpenVulkano::Scene static constexpr inline DescriptorSetLayoutBinding DESCRIPTOR_SET_LAYOUT_BINDING = { 0, DescriptorSetLayoutBinding::Type::TYPE_UNIFORM_BUFFER, 1, ShaderProgramType::ALL_GRAPHICS }; DescriptorSetLayoutBinding binding; - uint32_t setId = 2; + uint32_t setId; ICloseable* renderBuffer = nullptr; size_t size = 0; const void* data = nullptr; UpdateFrequency updateFrequency = UpdateFrequency::Never; bool updated = true; - void Init(size_t size, const void* data, const DescriptorSetLayoutBinding& binding = DESCRIPTOR_SET_LAYOUT_BINDING) + void Init(size_t size, const void* data, uint32_t setId = 2, const DescriptorSetLayoutBinding& binding = DESCRIPTOR_SET_LAYOUT_BINDING) { this->size = size; this->data = data; this->binding = binding; + this->setId = setId; } UpdateFrequency GetUpdateFrequency() const { return updateFrequency; } diff --git a/openVulkanoCpp/Shader/basicTexture.frag b/openVulkanoCpp/Shader/basicTexture.frag index acf99a1..d0095cc 100644 --- a/openVulkanoCpp/Shader/basicTexture.frag +++ b/openVulkanoCpp/Shader/basicTexture.frag @@ -3,6 +3,7 @@ layout(location = 0) in vec4 color; layout(location = 1) in vec2 texCoord; layout(location = 0) out vec4 outColor; + layout(set = 2, binding = 0) uniform sampler2D texSampler; void main() diff --git a/openVulkanoCpp/Shader/billboard.frag b/openVulkanoCpp/Shader/billboard.frag deleted file mode 100644 index 1a0e2cd..0000000 --- a/openVulkanoCpp/Shader/billboard.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 color; -layout(location = 0) out vec4 outColor; - -void main() -{ - outColor = color; -} \ No newline at end of file diff --git a/openVulkanoCpp/Shader/billboard.vert b/openVulkanoCpp/Shader/billboard.vert index 74787e8..261d543 100644 --- a/openVulkanoCpp/Shader/billboard.vert +++ b/openVulkanoCpp/Shader/billboard.vert @@ -1,9 +1,12 @@ #version 450 +#extension GL_ARB_separate_shader_objects : enable + layout(location = 0) in vec3 pos; -layout(location = 1) in vec3 normal; +layout(location = 4) in vec3 textureCoordinates; layout(location = 5) in vec4 color; layout(location = 0) out vec4 outColor; +layout(location = 1) out vec2 outTexture; layout(set = 0, binding = 0) uniform NodeData { @@ -13,15 +16,14 @@ layout(set = 0, binding = 0) uniform NodeData layout(set = 1, binding = 0) uniform CameraData { mat4 viewProjection; - mat4 view; - mat4 projection; - vec4 camPos; + mat4 view; + mat4 projection; + vec4 camPos; } cam; -layout(set = 2, binding = 0) uniform BillboardData +layout(set = 3, binding = 0) uniform BillboardData { vec2 size; - vec2 windowSize; bool isFixedSize; } billboardInfo; @@ -46,10 +48,11 @@ void main() { } else { - vec4 billboardPos = vec4(0, 0, 0, 1); + vec4 billboardPos = vec4(0.5, 0.5, 0.5, 1); vec4 viewPos = cam.view * node.world * billboardPos; float dist = -viewPos.z; gl_Position = cam.projection * (viewPos + vec4(pos.xy*dist*0.2,0,0)); } outColor = color; + outTexture = textureCoordinates.xy; } diff --git a/openVulkanoCpp/Shader/billboardFromSinglePoint.geom b/openVulkanoCpp/Shader/billboardFromSinglePoint.geom index 5c3d2cf..13e60f0 100644 --- a/openVulkanoCpp/Shader/billboardFromSinglePoint.geom +++ b/openVulkanoCpp/Shader/billboardFromSinglePoint.geom @@ -11,19 +11,27 @@ layout(set = 0, binding = 0) uniform NodeData layout(set = 1, binding = 0) uniform CameraData { mat4 viewProjection; - mat4 view; - mat4 projection; - vec4 camPos; + mat4 view; + mat4 projection; + vec4 camPos; + float nearPlane; + float farPlane; + float width; + float height; + float fov; + float aspect; + float scaleFactor; + float pixelScaleFactor; } cam; -layout(set = 2, binding = 0) uniform BillboardData +layout(set = 3, binding = 0) uniform BillboardData { vec2 size; - vec2 windowSize; bool isFixedSize; } billboardInfo; layout(location = 0) out vec4 color; +layout(location = 1) out vec2 tex; layout(location = 0) in VS_OUT { vec4 color; @@ -32,7 +40,6 @@ layout(location = 0) in VS_OUT { void main() { // The desired point for the billboard vec3 pos = gl_in[0].gl_Position.xyz; - if(!billboardInfo.isFixedSize) { vec3 cameraRight = normalize(vec3(cam.view[0][0], cam.view[1][0], cam.view[2][0])); @@ -43,12 +50,19 @@ void main() { vec2(-0.5, -0.5), vec2(-0.5, 0.5) }; + const vec2 texCoords[4] = { + vec2(1, 0), + vec2(1, 1), + vec2(0, 0), + vec2(0, 1) + }; for (int i = 0; i < 4; i++) { vec2 scaledSize = billboardInfo.size / length(billboardInfo.size); gl_Position = cam.viewProjection * vec4(pos + cameraRight * offsets[i].x * scaledSize.x + cameraUp * offsets[i].y * scaledSize.y, 1.0); color = gs_in[0].color; + tex = texCoords[i].xy; EmitVertex(); } EndPrimitive(); @@ -61,13 +75,20 @@ void main() { vec2(0.5, -0.5), vec2(0.5, 0.5) }; + const vec2 texCoords[4] = { + vec2(0, 0), + vec2(0, 1), + vec2(1, 0), + vec2(1, 1) + }; for (int i = 0; i < 4; i++) { gl_Position = cam.viewProjection * vec4(pos, 1); gl_Position /= gl_Position.w; - gl_Position.xy += offsets[i] * vec2(billboardInfo.size.x/billboardInfo.windowSize.x, billboardInfo.size.x/billboardInfo.windowSize.y); + gl_Position.xy += offsets[i] * vec2(billboardInfo.size.x/cam.width, billboardInfo.size.x/cam.height); color = gs_in[0].color; + tex = texCoords[i].xy; EmitVertex(); } EndPrimitive(); diff --git a/openVulkanoCpp/Shader/billboardFromSinglePoint.vert b/openVulkanoCpp/Shader/billboardFromSinglePoint.vert index 3ad4110..ee8e711 100644 --- a/openVulkanoCpp/Shader/billboardFromSinglePoint.vert +++ b/openVulkanoCpp/Shader/billboardFromSinglePoint.vert @@ -1,7 +1,8 @@ #version 450 +#extension GL_ARB_separate_shader_objects : enable + layout(location = 0) in vec3 pos; -layout(location = 1) in vec3 normal; layout(location = 5) in vec4 color; layout(location = 0) out VS_OUT { @@ -13,21 +14,6 @@ layout(set = 0, binding = 0) uniform NodeData mat4 world; } node; -layout(set = 1, binding = 0) uniform CameraData -{ - mat4 viewProjection; - mat4 view; - mat4 projection; - vec4 camPos; -} cam; - -layout(set = 2, binding = 0) uniform BillboardData -{ - vec2 size; - vec2 windowSize; - bool isFixedSize; -} billboardInfo; - void main() { // single point gl_Position = node.world * vec4(pos, 1);