diff --git a/include/vkcv/BufferManager.hpp b/include/vkcv/BufferManager.hpp index a390a2ff3be7f84b0c12f065398f9e40a42017e0..9eb80d70862a79a01593e6fe4c3aabe98d253ac8 100644 --- a/include/vkcv/BufferManager.hpp +++ b/include/vkcv/BufferManager.hpp @@ -132,6 +132,9 @@ namespace vkcv */ void unmapBuffer(const BufferHandle& handle); + void recordBufferMemoryBarrier( + const BufferHandle& handle, + vk::CommandBuffer cmdBuffer); }; } diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index bf9514d5ba4c9d5dbf8d41be2a489dae826886a8..dab18892b892aff9564a6d86b9252789ea3c2b03 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -63,9 +63,6 @@ namespace vkcv Context m_Context; Swapchain m_swapchain; - std::vector<vk::ImageView> m_swapchainImageViews; - std::vector<vk::Image> m_swapchainImages; - std::vector<vk::ImageLayout> m_swapchainImageLayouts; Window& m_window; std::unique_ptr<PassManager> m_PassManager; @@ -79,12 +76,10 @@ namespace vkcv CommandResources m_CommandResources; SyncResources m_SyncResources; uint32_t m_currentSwapchainImageIndex; - - event_handle<int,int> e_resizeHandle; - static std::vector<vk::ImageView> createImageViews( Context &context, Swapchain& swapChain); + event_handle<int,int> e_resizeHandle; - void recordSwapchainImageLayoutTransition(vk::CommandBuffer cmdBuffer, vk::ImageLayout newLayout); + static std::vector<vk::ImageView> createSwapchainImageViews( Context &context, Swapchain& swapChain); public: /** @@ -220,7 +215,7 @@ namespace vkcv * @return Image-Object */ [[nodiscard]] - Image createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth = 1); + Image createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth = 1, bool supportStorage = false, bool supportColorAttachment = false); /** TODO: * @param setDescriptions @@ -281,6 +276,9 @@ namespace vkcv void submitCommandStream(const CommandStreamHandle handle); void prepareSwapchainImageForPresent(const CommandStreamHandle handle); void prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image); + void prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image); + void recordImageMemoryBarrier(const CommandStreamHandle cmdStream, const ImageHandle image); + void recordBufferMemoryBarrier(const CommandStreamHandle cmdStream, const BufferHandle buffer); const vk::ImageView& getSwapchainImageView() const; diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 840650a1d6288922eceff7ba10ee7e71bf88dc22..1795b63e844a002564932f5d7ef839746e32fae5 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -42,7 +42,7 @@ namespace vkcv { Image(ImageManager* manager, const ImageHandle& handle); - static Image create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth); + static Image create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth, bool supportStorage, bool supportColorAttachment); }; diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp index 93523128a67d7b9667c342fb7c10203f4b9a43dd..1e00c5209118469a7dc6ff1eb1e3c98a3c6903a7 100644 --- a/include/vkcv/PipelineConfig.hpp +++ b/include/vkcv/PipelineConfig.hpp @@ -13,6 +13,8 @@ namespace vkcv { + enum class PrimitiveTopology{PointList, LineList, TriangleList }; + struct PipelineConfig { ShaderProgram m_ShaderProgram; uint32_t m_Width; @@ -21,7 +23,8 @@ namespace vkcv { VertexLayout m_VertexLayout; std::vector<vk::DescriptorSetLayout> m_DescriptorLayouts; bool m_UseDynamicViewport; - + bool m_UseConservativeRasterization = false; + PrimitiveTopology m_PrimitiveTopology = PrimitiveTopology::TriangleList; }; } \ No newline at end of file diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp index 096a857a13f01840d8a3a7e2bf74ba571bd2c249..6a08cb4f02551cae2fd5d1e3ea4e6ff0bd2b2e04 100644 --- a/modules/gui/src/vkcv/gui/GUI.cpp +++ b/modules/gui/src/vkcv/gui/GUI.cpp @@ -197,11 +197,13 @@ namespace vkcv::gui { const Swapchain& swapchain = m_core.getSwapchain(); const auto extent = swapchain.getExtent(); + const vk::ImageView swapchainImageView = m_core.getSwapchainImageView(); + const vk::FramebufferCreateInfo framebufferCreateInfo ( vk::FramebufferCreateFlags(), m_render_pass, 1, - &m_core.getSwapchainImageView(), + &swapchainImageView, extent.width, extent.height, 1 diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index 9e07dec255d283b4b8a8d4fcc769083498c10264..ec358188b8e871da6f4d62ffd397f32bfb795ee2 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -3,6 +3,7 @@ #include <fstream> #include <glslang/SPIRV/GlslangToSpv.h> +#include <glslang/StandAlone/DirStackFileIncluder.h> #include <vkcv/Logger.hpp> @@ -217,12 +218,26 @@ namespace vkcv::shader { TBuiltInResource resources = {}; initResources(resources); + + const auto messages = (EShMessages)( + EShMsgSpvRules | + EShMsgVulkanRules + ); + + std::string preprocessedGLSL; + + DirStackFileIncluder includer; + includer.pushExternalLocalDirectory(shaderPath.parent_path().string()); + + if (!shader.preprocess(&resources, 100, ENoProfile, false, false, messages, &preprocessedGLSL, includer)) { + vkcv_log(LogLevel::ERROR, "Shader parsing failed {\n%s\n%s\n} (%s)", + shader.getInfoLog(), shader.getInfoDebugLog(), shaderPath.string().c_str()); + return; + } - const auto messages = (EShMessages) ( - EShMsgSpvRules | - EShMsgVulkanRules - ); - + const char* preprocessedCString = preprocessedGLSL.c_str(); + shader.setStrings(&preprocessedCString, 1); + if (!shader.parse(&resources, 100, false, messages)) { vkcv_log(LogLevel::ERROR, "Shader parsing failed {\n%s\n%s\n} (%s)", shader.getInfoLog(), shader.getInfoDebugLog(), shaderPath.string().c_str()); diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index 474c9764bd29053c95ca2c4511d1287359350d02..99a3cb382ec02bab64e9fc714ceeb7e5cef39ed0 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -3,4 +3,4 @@ add_subdirectory(first_triangle) add_subdirectory(first_mesh) add_subdirectory(first_scene) -add_subdirectory(cmd_sync_test) \ No newline at end of file +add_subdirectory(voxelization) \ No newline at end of file diff --git a/projects/cmd_sync_test/.gitignore b/projects/cmd_sync_test/.gitignore deleted file mode 100644 index 16f72da367245ad14a38ee756816f06f8cbbe3d2..0000000000000000000000000000000000000000 --- a/projects/cmd_sync_test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cmd_sync_test \ No newline at end of file diff --git a/projects/cmd_sync_test/CMakeLists.txt b/projects/cmd_sync_test/CMakeLists.txt deleted file mode 100644 index da1d12949d9e8c918d78ab5cb0484106fae69b6a..0000000000000000000000000000000000000000 --- a/projects/cmd_sync_test/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(cmd_sync_test) - -# setting c++ standard for the project -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# this should fix the execution path to load local files from the project -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - -# adding source files to the project -add_executable(cmd_sync_test src/main.cpp) - -# this should fix the execution path to load local files from the project (for MSVC) -if(MSVC) - set_target_properties(cmd_sync_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - set_target_properties(cmd_sync_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) - - # in addition to setting the output directory, the working directory has to be set - # by default visual studio sets the working directory to the build directory, when using the debugger - set_target_properties(cmd_sync_test PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) -endif() - -# including headers of dependencies and the VkCV framework -target_include_directories(cmd_sync_test SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include}) - -# linking with libraries from all dependencies and the VkCV framework -target_link_libraries(cmd_sync_test vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera) diff --git a/projects/cmd_sync_test/resources/shaders/compile.bat b/projects/cmd_sync_test/resources/shaders/compile.bat deleted file mode 100644 index 516c2f2f78001e1a5d182356e7c3fe82d66a45ee..0000000000000000000000000000000000000000 --- a/projects/cmd_sync_test/resources/shaders/compile.bat +++ /dev/null @@ -1,5 +0,0 @@ -%VULKAN_SDK%\Bin32\glslc.exe shader.vert -o vert.spv -%VULKAN_SDK%\Bin32\glslc.exe shader.frag -o frag.spv -%VULKAN_SDK%\Bin32\glslc.exe shadow.vert -o shadow_vert.spv -%VULKAN_SDK%\Bin32\glslc.exe shadow.frag -o shadow_frag.spv -pause \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/frag.spv b/projects/cmd_sync_test/resources/shaders/frag.spv deleted file mode 100644 index ff3110571871d65ce119dc6c5006e7e67aa53546..0000000000000000000000000000000000000000 Binary files a/projects/cmd_sync_test/resources/shaders/frag.spv and /dev/null differ diff --git a/projects/cmd_sync_test/resources/shaders/shadow_frag.spv b/projects/cmd_sync_test/resources/shaders/shadow_frag.spv deleted file mode 100644 index 6be3bd2518a3b1f234e39aea2503ba86cfb3314b..0000000000000000000000000000000000000000 Binary files a/projects/cmd_sync_test/resources/shaders/shadow_frag.spv and /dev/null differ diff --git a/projects/cmd_sync_test/resources/shaders/shadow_vert.spv b/projects/cmd_sync_test/resources/shaders/shadow_vert.spv deleted file mode 100644 index afaa0824ee9be2c22209d611943c6512587dce24..0000000000000000000000000000000000000000 Binary files a/projects/cmd_sync_test/resources/shaders/shadow_vert.spv and /dev/null differ diff --git a/projects/cmd_sync_test/resources/shaders/vert.spv b/projects/cmd_sync_test/resources/shaders/vert.spv deleted file mode 100644 index 5e514eef5983927316465679af5461f507497130..0000000000000000000000000000000000000000 Binary files a/projects/cmd_sync_test/resources/shaders/vert.spv and /dev/null differ diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 6377a6726d3e9d1830518206133dd7780593d576..d9650f3577cf5633ac915f435b59367a9f993d62 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -137,8 +137,9 @@ int main(int argc, const char** argv) { vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) }; vkcv::DescriptorWrites setWrites; - setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; - setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + setWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) }; + setWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(1, sampler) }; + core.writeDescriptorSet(descriptorSet, setWrites); vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); diff --git a/projects/voxelization/.gitignore b/projects/voxelization/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f07a22d4e0641a9114e998212f38ca9cb83a9655 --- /dev/null +++ b/projects/voxelization/.gitignore @@ -0,0 +1 @@ +voxelization \ No newline at end of file diff --git a/projects/voxelization/CMakeLists.txt b/projects/voxelization/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..33cfaef6197079b72ab2f295a4503e80be724db4 --- /dev/null +++ b/projects/voxelization/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.16) +project(voxelization) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(voxelization src/main.cpp) + +target_sources(voxelization PRIVATE + src/Voxelization.hpp + src/Voxelization.cpp) + +# this should fix the execution path to load local files from the project (for MSVC) +if(MSVC) + set_target_properties(voxelization PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set_target_properties(voxelization PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + # in addition to setting the output directory, the working directory has to be set + # by default visual studio sets the working directory to the build directory, when using the debugger + set_target_properties(voxelization PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +# including headers of dependencies and the VkCV framework +target_include_directories(voxelization SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(voxelization vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_shader_compiler) diff --git a/projects/voxelization/resources/Sponza/Sponza.bin b/projects/voxelization/resources/Sponza/Sponza.bin new file mode 100644 index 0000000000000000000000000000000000000000..cfedd26ca5a67b6d0a47d44d13a75e14a141717a --- /dev/null +++ b/projects/voxelization/resources/Sponza/Sponza.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b809f7a17687dc99e6f41ca1ea32c06eded8779bf34d16f1f565d750b0ffd68 +size 6347696 diff --git a/projects/voxelization/resources/Sponza/Sponza.gltf b/projects/voxelization/resources/Sponza/Sponza.gltf new file mode 100644 index 0000000000000000000000000000000000000000..172ea07e21c94465211c860cd805355704cef230 --- /dev/null +++ b/projects/voxelization/resources/Sponza/Sponza.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5cc0ecad5c4694088ff820e663619c370421afc1323ac487406e8e9b4735d787 +size 713962 diff --git a/projects/voxelization/resources/Sponza/background.png b/projects/voxelization/resources/Sponza/background.png new file mode 100644 index 0000000000000000000000000000000000000000..b64def129da38f4e23d89e21b4af1039008a4327 --- /dev/null +++ b/projects/voxelization/resources/Sponza/background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5b5f900ff8ed83a31750ec8e428b5b91273794ddcbfc4e4b8a6a7e781f8c686 +size 1417666 diff --git a/projects/voxelization/resources/Sponza/chain_texture.png b/projects/voxelization/resources/Sponza/chain_texture.png new file mode 100644 index 0000000000000000000000000000000000000000..c1e1768cff78e0614ad707eca8602a4c4edab5e5 --- /dev/null +++ b/projects/voxelization/resources/Sponza/chain_texture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8362cfd472880daeaea37439326a4651d1338680ae69bb2513fc6b17c8de7d4 +size 490895 diff --git a/projects/voxelization/resources/Sponza/lion.png b/projects/voxelization/resources/Sponza/lion.png new file mode 100644 index 0000000000000000000000000000000000000000..c49c7f0ed31e762e19284d0d3624fbc47664e56b --- /dev/null +++ b/projects/voxelization/resources/Sponza/lion.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f882f746c3a9cd51a9c6eedc1189b97668721d91a3fe49232036e789912c652 +size 2088728 diff --git a/projects/voxelization/resources/Sponza/spnza_bricks_a_diff.png b/projects/voxelization/resources/Sponza/spnza_bricks_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..cde4c7a6511e9a5f03c63ad996437fcdba3ce2df --- /dev/null +++ b/projects/voxelization/resources/Sponza/spnza_bricks_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b94219c2f5f943f3f4715c74e7d1038bf0ab3b3b3216a758eaee67f875df0851 +size 1928829 diff --git a/projects/voxelization/resources/Sponza/sponza_arch_diff.png b/projects/voxelization/resources/Sponza/sponza_arch_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..bcd9bda2918d226039f9e2d03902d377b706fab6 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_arch_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0df2c8a01b2843b1c792b494f7173cdbc4f834840fc2177af3e5d690fceda57 +size 1596151 diff --git a/projects/voxelization/resources/Sponza/sponza_ceiling_a_diff.png b/projects/voxelization/resources/Sponza/sponza_ceiling_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..59de631ffac4414cabf69b2dc794c46fc187d6cb --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_ceiling_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab6c187a81aa68f4eba30119e17fce2e4882a9ec320f70c90482dbe9da82b1c6 +size 1872074 diff --git a/projects/voxelization/resources/Sponza/sponza_column_a_diff.png b/projects/voxelization/resources/Sponza/sponza_column_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..01a82432d3f9939bbefe850bdb900f1ff9a3f6db --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_column_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c291507e2808bb83e160ab4b020689817df273baad3713a9ad19ac15fac6826 +size 1840992 diff --git a/projects/voxelization/resources/Sponza/sponza_column_b_diff.png b/projects/voxelization/resources/Sponza/sponza_column_b_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..10a660cce2a5a9b8997772c746058ce23e7d45d7 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_column_b_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2820b0267c4289c6cedbb42721792a57ef244ec2d0935941011c2a7d3fe88a9b +size 2170433 diff --git a/projects/voxelization/resources/Sponza/sponza_column_c_diff.png b/projects/voxelization/resources/Sponza/sponza_column_c_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..bc46fd979044a938d3adca7601689e71504e48bf --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_column_c_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0bc993ff59865468ef4530798930c7dfefb07482d71db45bc2a520986b27735 +size 2066950 diff --git a/projects/voxelization/resources/Sponza/sponza_curtain_blue_diff.png b/projects/voxelization/resources/Sponza/sponza_curtain_blue_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..384c8c2c051160d530eb3ac8b05c9c60752a2d2b --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_curtain_blue_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b85c6bb3cd5105f48d3812ec8e7a1068521ce69e917300d79e136e19d45422fb +size 9510905 diff --git a/projects/voxelization/resources/Sponza/sponza_curtain_diff.png b/projects/voxelization/resources/Sponza/sponza_curtain_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..af842e9f5fe18c1f609875e00899a6770fa4488b --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_curtain_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:563c56bdbbee395a6ef7f0c51c8ac9223c162e517b4cdba0d4654e8de27c98d8 +size 9189263 diff --git a/projects/voxelization/resources/Sponza/sponza_curtain_green_diff.png b/projects/voxelization/resources/Sponza/sponza_curtain_green_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..6c9b6391a199407637fa71033d79fb58b8b4f0d7 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_curtain_green_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:238fe1c7f481388d1c1d578c2da8d411b99e8f0030ab62060a306db333124476 +size 8785458 diff --git a/projects/voxelization/resources/Sponza/sponza_details_diff.png b/projects/voxelization/resources/Sponza/sponza_details_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..12656686362c3e0a297e060491f33bd7351551f9 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_details_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb1223b3bb82f8757e7df25a6891f1239cdd7ec59990340e952fb2d6b7ea570c +size 1522643 diff --git a/projects/voxelization/resources/Sponza/sponza_fabric_blue_diff.png b/projects/voxelization/resources/Sponza/sponza_fabric_blue_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..879d16ef84722a4fc13e83a771778de326e4bc54 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_fabric_blue_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:467d290bf5d4b2a017da140ba9e244ed8a8a9be5418a9ac9bcb4ad572ae2d7ab +size 2229440 diff --git a/projects/voxelization/resources/Sponza/sponza_fabric_diff.png b/projects/voxelization/resources/Sponza/sponza_fabric_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..3311287a219d2148620b87fe428fea071688d051 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_fabric_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1594f59cc2848db26add47361f4e665e3d8afa147760ed915d839fea42b20287 +size 2267382 diff --git a/projects/voxelization/resources/Sponza/sponza_fabric_green_diff.png b/projects/voxelization/resources/Sponza/sponza_fabric_green_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..de110f369004388dae4cd5067c63428db3a07834 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_fabric_green_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:902b87faab221173bf370cea7c74cb9060b4d870ac6316b190dafded1cb12993 +size 2258220 diff --git a/projects/voxelization/resources/Sponza/sponza_flagpole_diff.png b/projects/voxelization/resources/Sponza/sponza_flagpole_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6e0812a0df80346318baa3cb50a6888afc58f8 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_flagpole_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bfffb62e770959c725d0f3db6dc7dbdd46a380ec55ef884dab94d44ca017b438 +size 1425673 diff --git a/projects/voxelization/resources/Sponza/sponza_floor_a_diff.png b/projects/voxelization/resources/Sponza/sponza_floor_a_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..788ed764f79ba724f04a2d603076a5b85013e188 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_floor_a_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a16f9230fa91f9f31dfca6216ce205f1ef132d44f3b012fbf6efc0fba69770ab +size 1996838 diff --git a/projects/voxelization/resources/Sponza/sponza_roof_diff.png b/projects/voxelization/resources/Sponza/sponza_roof_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..c5b84261fdd1cc776a94b3ce398c7806b895f9a3 --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_roof_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7fc412138c20da19f8173e53545e771f4652558dff624d4dc67143e40efe562b +size 2320533 diff --git a/projects/voxelization/resources/Sponza/sponza_thorn_diff.png b/projects/voxelization/resources/Sponza/sponza_thorn_diff.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9142674a7d4a6f94a48c5152cf0300743b597a --- /dev/null +++ b/projects/voxelization/resources/Sponza/sponza_thorn_diff.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a73a17c883cd0d0d67cfda2dc4118400a916366c05b9a5ac465f0c8b30fd9c8e +size 635001 diff --git a/projects/voxelization/resources/Sponza/vase_dif.png b/projects/voxelization/resources/Sponza/vase_dif.png new file mode 100644 index 0000000000000000000000000000000000000000..61236a81cb324af8797b05099cd264cefe189e56 --- /dev/null +++ b/projects/voxelization/resources/Sponza/vase_dif.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53d06f52bf9e59df4cf00237707cca76c4f692bda61a62b06a30d321311d6dd9 +size 1842101 diff --git a/projects/voxelization/resources/Sponza/vase_hanging.png b/projects/voxelization/resources/Sponza/vase_hanging.png new file mode 100644 index 0000000000000000000000000000000000000000..36a3cee71d8213225090c74f8c0dce33b9d44378 --- /dev/null +++ b/projects/voxelization/resources/Sponza/vase_hanging.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a9d10b4f27a3c9a78d5bac882fdd4b6a6987c262f48fa490670fe5e235951e31 +size 1432804 diff --git a/projects/voxelization/resources/Sponza/vase_plant.png b/projects/voxelization/resources/Sponza/vase_plant.png new file mode 100644 index 0000000000000000000000000000000000000000..7ad95e702e229f1ebd803e5203a266d15f2c07b9 --- /dev/null +++ b/projects/voxelization/resources/Sponza/vase_plant.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2087371ff02212fb7014b6daefa191cf5676d2227193fff261a5d02f554cb8e +size 998089 diff --git a/projects/voxelization/resources/Sponza/vase_round.png b/projects/voxelization/resources/Sponza/vase_round.png new file mode 100644 index 0000000000000000000000000000000000000000..c17953abc000c44b8991e23c136c2b67348f3d1b --- /dev/null +++ b/projects/voxelization/resources/Sponza/vase_round.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa23d48d492d5d4ada2ddb27d1ef22952b214e6eb3b301c65f9d88442723d20a +size 1871399 diff --git a/projects/cmd_sync_test/resources/cube/boards2_vcyc_jpg.jpg b/projects/voxelization/resources/cube/boards2_vcyc_jpg.jpg similarity index 100% rename from projects/cmd_sync_test/resources/cube/boards2_vcyc_jpg.jpg rename to projects/voxelization/resources/cube/boards2_vcyc_jpg.jpg diff --git a/projects/cmd_sync_test/resources/cube/cube.bin b/projects/voxelization/resources/cube/cube.bin similarity index 100% rename from projects/cmd_sync_test/resources/cube/cube.bin rename to projects/voxelization/resources/cube/cube.bin diff --git a/projects/cmd_sync_test/resources/cube/cube.blend b/projects/voxelization/resources/cube/cube.blend similarity index 100% rename from projects/cmd_sync_test/resources/cube/cube.blend rename to projects/voxelization/resources/cube/cube.blend diff --git a/projects/cmd_sync_test/resources/cube/cube.blend1 b/projects/voxelization/resources/cube/cube.blend1 similarity index 100% rename from projects/cmd_sync_test/resources/cube/cube.blend1 rename to projects/voxelization/resources/cube/cube.blend1 diff --git a/projects/cmd_sync_test/resources/cube/cube.glb b/projects/voxelization/resources/cube/cube.glb similarity index 100% rename from projects/cmd_sync_test/resources/cube/cube.glb rename to projects/voxelization/resources/cube/cube.glb diff --git a/projects/cmd_sync_test/resources/cube/cube.gltf b/projects/voxelization/resources/cube/cube.gltf similarity index 100% rename from projects/cmd_sync_test/resources/cube/cube.gltf rename to projects/voxelization/resources/cube/cube.gltf diff --git a/projects/voxelization/resources/shaders/gammaCorrection.comp b/projects/voxelization/resources/shaders/gammaCorrection.comp new file mode 100644 index 0000000000000000000000000000000000000000..411a59c3e38b3414adbda260803c3f3322b16ff2 --- /dev/null +++ b/projects/voxelization/resources/shaders/gammaCorrection.comp @@ -0,0 +1,18 @@ +#version 440 + +layout(set=0, binding=0, r11f_g11f_b10f) uniform image2D inImage; +layout(set=0, binding=1, rgba8) uniform image2D outImage; + + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main(){ + + if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(inImage)))){ + return; + } + ivec2 uv = ivec2(gl_GlobalInvocationID.xy); + vec3 linearColor = imageLoad(inImage, uv).rgb; + vec3 gammaCorrected = pow(linearColor, vec3(1.f / 2.2f)); + imageStore(outImage, uv, vec4(gammaCorrected, 0.f)); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/perMeshResources.inc b/projects/voxelization/resources/shaders/perMeshResources.inc new file mode 100644 index 0000000000000000000000000000000000000000..95e4fb7c27009965659d14a9c72acfec950c37e3 --- /dev/null +++ b/projects/voxelization/resources/shaders/perMeshResources.inc @@ -0,0 +1,2 @@ +layout(set=1, binding=0) uniform texture2D albedoTexture; +layout(set=1, binding=1) uniform sampler textureSampler; \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shader.frag b/projects/voxelization/resources/shaders/shader.frag similarity index 74% rename from projects/cmd_sync_test/resources/shaders/shader.frag rename to projects/voxelization/resources/shaders/shader.frag index 95f1b3319e1ca5c7c34ff94e5e7198819c0233c1..edafc8c0077416cb57aedc4e7358126846507e18 100644 --- a/projects/cmd_sync_test/resources/shaders/shader.frag +++ b/projects/voxelization/resources/shaders/shader.frag @@ -1,5 +1,8 @@ #version 450 #extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +#include "perMeshResources.inc" layout(location = 0) in vec3 passNormal; layout(location = 1) in vec2 passUV; @@ -7,14 +10,12 @@ layout(location = 2) in vec3 passPos; layout(location = 0) out vec3 outColor; -layout(set=0, binding=0) uniform texture2D meshTexture; -layout(set=0, binding=1) uniform sampler textureSampler; -layout(set=0, binding=2) uniform sunBuffer { +layout(set=0, binding=0) uniform sunBuffer { vec3 L; float padding; mat4 lightMatrix; }; -layout(set=0, binding=3) uniform texture2D shadowMap; -layout(set=0, binding=4) uniform sampler shadowMapSampler; +layout(set=0, binding=1) uniform texture2D shadowMap; +layout(set=0, binding=2) uniform sampler shadowMapSampler; float shadowTest(vec3 worldPos){ vec4 lightPos = lightMatrix * vec4(worldPos, 1); @@ -39,6 +40,6 @@ void main() { vec3 sun = sunColor * clamp(dot(N, L), 0, 1); sun *= shadowTest(passPos); vec3 ambient = vec3(0.1); - vec3 albedo = texture(sampler2D(meshTexture, textureSampler), passUV).rgb; + vec3 albedo = texture(sampler2D(albedoTexture, textureSampler), passUV).rgb; outColor = albedo * (sun + ambient); } \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shader.vert b/projects/voxelization/resources/shaders/shader.vert similarity index 82% rename from projects/cmd_sync_test/resources/shaders/shader.vert rename to projects/voxelization/resources/shaders/shader.vert index 0ab82c203806356d0f35dc52c0a6988b286d90d1..926f86af2860cb57c44d2d5ee78712b6ae155e5c 100644 --- a/projects/cmd_sync_test/resources/shaders/shader.vert +++ b/projects/voxelization/resources/shaders/shader.vert @@ -16,7 +16,7 @@ layout( push_constant ) uniform constants{ void main() { gl_Position = mvp * vec4(inPosition, 1.0); - passNormal = inNormal; + passNormal = mat3(model) * inNormal; // assuming no weird stuff like shearing or non-uniform scaling passUV = inUV; passPos = (model * vec4(inPosition, 1)).xyz; } \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/shaders/shadow.frag b/projects/voxelization/resources/shaders/shadow.frag similarity index 100% rename from projects/cmd_sync_test/resources/shaders/shadow.frag rename to projects/voxelization/resources/shaders/shadow.frag diff --git a/projects/cmd_sync_test/resources/shaders/shadow.vert b/projects/voxelization/resources/shaders/shadow.vert similarity index 100% rename from projects/cmd_sync_test/resources/shaders/shadow.vert rename to projects/voxelization/resources/shaders/shadow.vert diff --git a/projects/voxelization/resources/shaders/voxel.inc b/projects/voxelization/resources/shaders/voxel.inc new file mode 100644 index 0000000000000000000000000000000000000000..d2b4400235817e3be1739dc46857ab42f260ebf7 --- /dev/null +++ b/projects/voxelization/resources/shaders/voxel.inc @@ -0,0 +1,25 @@ +struct VoxelInfo{ + vec3 offset; + float extent; +}; + +uint flattenVoxelUVToIndex(ivec3 UV, ivec3 voxelImageSize){ + return UV.x + UV.y * voxelImageSize.x + UV.z * voxelImageSize.x* voxelImageSize.y; +} + +uint packVoxelInfo(vec3 color){ + uint opaqueBit = 1 << 31; + uint redBits = uint(color.r * 255); + uint greenBits = uint(color.g * 255) << 8; + uint blueBits = uint(color.b * 255) << 16; + return opaqueBit | redBits | greenBits | blueBits; +} + +vec4 unpackVoxelInfo(uint packed){ + vec4 rgba; + rgba.r = (packed >> 0 & 0x000000FF) / 255.f; + rgba.g = (packed >> 8 & 0x000000FF) / 255.f; + rgba.b = (packed >> 16 & 0x000000FF) / 255.f; + rgba.a = packed >> 31; + return rgba; +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelBufferToImage.comp b/projects/voxelization/resources/shaders/voxelBufferToImage.comp new file mode 100644 index 0000000000000000000000000000000000000000..5e8298886cb2bacbc81f981e8e90310cdc876d5d --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelBufferToImage.comp @@ -0,0 +1,24 @@ +#version 450 +#extension GL_GOOGLE_include_directive : enable +#include "voxel.inc" + +layout(set=0, binding=0, std430) buffer voxelBuffer{ + uint packedVoxelData[]; +}; + +layout(set=0, binding=1, rgba16f) uniform image3D voxelImage; + +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; + +void main(){ + + ivec3 voxelImageSize = imageSize(voxelImage); + if(any(greaterThanEqual(gl_GlobalInvocationID, voxelImageSize))){ + return; + } + ivec3 UV = ivec3(gl_GlobalInvocationID); + uint flatIndex = flattenVoxelUVToIndex(UV, voxelImageSize); + + vec4 color = unpackVoxelInfo(packedVoxelData[flatIndex]); + imageStore(voxelImage, UV, vec4(color)); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelReset.comp b/projects/voxelization/resources/shaders/voxelReset.comp new file mode 100644 index 0000000000000000000000000000000000000000..14b78d6584d703be68594e3cb03ebcd47c94b6e0 --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelReset.comp @@ -0,0 +1,19 @@ +#version 450 + +layout(set=0, binding=0) buffer voxelizationBuffer{ + uint isFilled[]; +}; + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout( push_constant ) uniform constants{ + uint voxelCount; +}; + +void main(){ + + if(gl_GlobalInvocationID.x> voxelCount){ + return; + } + isFilled[gl_GlobalInvocationID.x] = 0; +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelVisualisation.frag b/projects/voxelization/resources/shaders/voxelVisualisation.frag new file mode 100644 index 0000000000000000000000000000000000000000..0b02beb7e848ab20cda4b012f77d1fa664b6ab53 --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelVisualisation.frag @@ -0,0 +1,9 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location=0) in vec3 passColorToFrag; +layout(location=0) out vec3 outColor; + +void main() { + outColor = passColorToFrag; +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelVisualisation.geom b/projects/voxelization/resources/shaders/voxelVisualisation.geom new file mode 100644 index 0000000000000000000000000000000000000000..e98076fcc83a69a903df454cb00267da84e3f223 --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelVisualisation.geom @@ -0,0 +1,104 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(points) in; +layout (triangle_strip, max_vertices = 24) out; + +layout( push_constant ) uniform constants{ + mat4 viewProjection; +}; + +layout(location = 0) in float passCubeHalf[1]; +layout(location = 1) in vec3 passColorToGeom[1]; + + +layout(location = 0) out vec3 passColorToFrag; + +void main() { + float cubeHalf = passCubeHalf[0]; + // right + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + EndPrimitive(); + // left + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + EndPrimitive(); + // back + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + EndPrimitive(); + // front + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + EndPrimitive(); + // bot + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, 1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, 1, -1), 1); + passColorToFrag = passColorToGeom[0]; + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + EndPrimitive(); + // top + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(1, -1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, 1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + gl_Position = viewProjection * vec4(gl_in[0].gl_Position.xyz + cubeHalf * vec3(-1, -1, -1), 1); + passColorToFrag = passColorToGeom[0]; + EmitVertex(); + EndPrimitive(); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelVisualisation.vert b/projects/voxelization/resources/shaders/voxelVisualisation.vert new file mode 100644 index 0000000000000000000000000000000000000000..8377143f4f4bbf351d3251df9724d37e1747a4dc --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelVisualisation.vert @@ -0,0 +1,36 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +#include "voxel.inc" + +layout(location = 0) out float passCubeHalf; +layout(location = 1) out vec3 passColorToGeom; + +layout( push_constant ) uniform constants{ + mat4 viewProjection; +}; + +layout(set=0, binding=0, rgba16f) uniform image3D voxelImage; +layout(set=0, binding=1) uniform voxelizationInfo{ + VoxelInfo voxelInfo; +}; + + +void main() { + passCubeHalf = voxelInfo.extent / float(imageSize(voxelImage).x) * 0.5f; + int voxelResolution = imageSize(voxelImage).x; + int slicePixelCount = voxelResolution * voxelResolution; + int z = gl_VertexIndex / slicePixelCount; + int index2D = gl_VertexIndex % slicePixelCount; + int y = index2D / voxelResolution; + int x = index2D % voxelResolution; + vec3 position = (vec3(x, y, z) / voxelResolution - 0.5) * voxelInfo.extent + passCubeHalf + voxelInfo.offset; + gl_Position = vec4(position, 1.0); + + vec4 voxelColor = imageLoad(voxelImage, ivec3(x,y,z)); + if(voxelColor.a == 0){ + gl_Position.x /= 0; // clip + } + passColorToGeom = voxelColor.rgb; +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelization.frag b/projects/voxelization/resources/shaders/voxelization.frag new file mode 100644 index 0000000000000000000000000000000000000000..7ea161ce4f5a4d59bb3d50c78553df0dfb5ab4ec --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelization.frag @@ -0,0 +1,40 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +#include "voxel.inc" +#include "perMeshResources.inc" + +layout(location = 0) in vec3 passPos; +layout(location = 1) out vec2 passUV; + +layout(set=0, binding=0, std430) buffer voxelizationBuffer{ + uint packedVoxelData[]; +}; + +layout(set=0, binding=1) uniform voxelizationInfo{ + VoxelInfo voxelInfo; +}; + +layout(set=0, binding=2, r8) uniform image3D voxelImage; + +vec3 worldToVoxelCoordinates(vec3 world, VoxelInfo info){ + return (world - info.offset) / info.extent + 0.5f; +} + +ivec3 voxelCoordinatesToUV(vec3 voxelCoordinates, ivec3 voxelImageResolution){ + return ivec3(voxelCoordinates * voxelImageResolution); +} + +void main() { + vec3 voxelCoordinates = worldToVoxelCoordinates(passPos, voxelInfo); + ivec3 voxelImageSize = imageSize(voxelImage); + ivec3 UV = voxelCoordinatesToUV(voxelCoordinates, voxelImageSize); + if(any(lessThan(UV, ivec3(0))) || any(greaterThanEqual(UV, voxelImageSize))){ + return; + } + uint flatIndex = flattenVoxelUVToIndex(UV, voxelImageSize); + + vec3 color = texture(sampler2D(albedoTexture, textureSampler), passUV).rgb; + atomicMax(packedVoxelData[flatIndex], packVoxelInfo(color)); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelization.geom b/projects/voxelization/resources/shaders/voxelization.geom new file mode 100644 index 0000000000000000000000000000000000000000..19e31e2d2d032b5a9e5c273f6420c6449be9203e --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelization.geom @@ -0,0 +1,35 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(triangles) in; +layout (triangle_strip, max_vertices = 3) out; + +layout(location = 0) in vec3 passPosIn[3]; +layout(location = 1) in vec2 passUVIn[3]; + +layout(location = 0) out vec3 passPos; +layout(location = 1) out vec2 passUV; + +void main() { + // compute geometric normal, no normalization necessary + vec3 N = cross(passPosIn[0] - passPosIn[1], passPosIn[0] - passPosIn[2]); + N = abs(N); // only interested in the magnitude + + for(int i = 0; i < 3; i++){ + // swizzle position, so biggest side is rasterized + if(N.z > N.x && N.z > N.y){ + gl_Position = gl_in[i].gl_Position.xyzw; + } + else if(N.x > N.y){ + gl_Position = gl_in[i].gl_Position.yzxw; + } + else{ + gl_Position = gl_in[i].gl_Position.xzyw; + } + gl_Position.z = gl_Position.z * 0.5 + 0.5; // xyz are kept in NDC range [-1, 1] so swizzling works, but vulkan needs final z in range [0, 1] + passPos = passPosIn[i]; + passUV = passUVIn[i]; + EmitVertex(); + } + EndPrimitive(); +} \ No newline at end of file diff --git a/projects/voxelization/resources/shaders/voxelization.vert b/projects/voxelization/resources/shaders/voxelization.vert new file mode 100644 index 0000000000000000000000000000000000000000..7a43c08b64d3df384d3a7e627d789db9be99f680 --- /dev/null +++ b/projects/voxelization/resources/shaders/voxelization.vert @@ -0,0 +1,20 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec2 inUV; + +layout(location = 0) out vec3 passPos; +layout(location = 1) out vec2 passUV; + +layout( push_constant ) uniform constants{ + mat4 mvp; + mat4 model; +}; + +void main() { + gl_Position = mvp * vec4(inPosition, 1.0); + passPos = (model * vec4(inPosition, 1)).xyz; + passUV = inUV; +} \ No newline at end of file diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.bin b/projects/voxelization/resources/triangle/Triangle.bin similarity index 100% rename from projects/cmd_sync_test/resources/triangle/Triangle.bin rename to projects/voxelization/resources/triangle/Triangle.bin diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.blend b/projects/voxelization/resources/triangle/Triangle.blend similarity index 100% rename from projects/cmd_sync_test/resources/triangle/Triangle.blend rename to projects/voxelization/resources/triangle/Triangle.blend diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.glb b/projects/voxelization/resources/triangle/Triangle.glb similarity index 100% rename from projects/cmd_sync_test/resources/triangle/Triangle.glb rename to projects/voxelization/resources/triangle/Triangle.glb diff --git a/projects/cmd_sync_test/resources/triangle/Triangle.gltf b/projects/voxelization/resources/triangle/Triangle.gltf similarity index 100% rename from projects/cmd_sync_test/resources/triangle/Triangle.gltf rename to projects/voxelization/resources/triangle/Triangle.gltf diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a67177447ec3b795c3c65476e6881b067a33df84 --- /dev/null +++ b/projects/voxelization/src/Voxelization.cpp @@ -0,0 +1,285 @@ +#include "Voxelization.hpp" +#include <vkcv/shader/GLSLCompiler.hpp> +#include <glm/gtc/matrix_transform.hpp> + +vkcv::ShaderProgram loadVoxelizationShader() { + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram shader; + compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/voxelization.vert", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::GEOMETRY, "resources/shaders/voxelization.geom", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/voxelization.frag", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + return shader; +} + +vkcv::ShaderProgram loadVoxelVisualisationShader() { + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram shader; + compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/voxelVisualisation.vert", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::GEOMETRY, "resources/shaders/voxelVisualisation.geom", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/voxelVisualisation.frag", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + return shader; +} + +vkcv::ShaderProgram loadVoxelResetShader() { + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram shader; + compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/voxelReset.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + return shader; +} + +vkcv::ShaderProgram loadVoxelBufferToImageShader() { + vkcv::shader::GLSLCompiler compiler; + vkcv::ShaderProgram shader; + compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/voxelBufferToImage.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shader.addShader(shaderStage, path); + }); + return shader; +} + +const uint32_t voxelResolution = 128; +uint32_t voxelCount = voxelResolution * voxelResolution * voxelResolution; +const vk::Format voxelizationDummyFormat = vk::Format::eR8Unorm; + +Voxelization::Voxelization(vkcv::Core* corePtr, const Dependencies& dependencies) + : + m_corePtr(corePtr), + m_voxelImage(m_corePtr->createImage(vk::Format::eR16G16B16A16Sfloat, voxelResolution, voxelResolution, voxelResolution, true)), + m_dummyRenderTarget(m_corePtr->createImage(voxelizationDummyFormat, voxelResolution, voxelResolution, 1, false, true)), + m_voxelInfoBuffer(m_corePtr->createBuffer<VoxelizationInfo>(vkcv::BufferType::UNIFORM, 1)), + m_voxelBuffer(m_corePtr->createBuffer<VoxelBufferContent>(vkcv::BufferType::STORAGE, voxelCount)){ + + const vkcv::ShaderProgram voxelizationShader = loadVoxelizationShader(); + + const vkcv::PassConfig voxelizationPassConfig({vkcv::AttachmentDescription( + vkcv::AttachmentOperation::DONT_CARE, + vkcv::AttachmentOperation::DONT_CARE, + voxelizationDummyFormat) }); + m_voxelizationPass = m_corePtr->createPass(voxelizationPassConfig); + + std::vector<vkcv::DescriptorBinding> voxelizationDescriptorBindings = + { voxelizationShader.getReflectedDescriptors()[0] }; + m_voxelizationDescriptorSet = m_corePtr->createDescriptorSet(voxelizationDescriptorBindings); + + vkcv::DescriptorSetHandle dummyPerMeshDescriptorSet = + m_corePtr->createDescriptorSet({ voxelizationShader.getReflectedDescriptors()[1] }); + + const vkcv::PipelineConfig voxelizationPipeConfig{ + voxelizationShader, + voxelResolution, + voxelResolution, + m_voxelizationPass, + dependencies.vertexLayout, + { + m_corePtr->getDescriptorSet(m_voxelizationDescriptorSet).layout, + m_corePtr->getDescriptorSet(dummyPerMeshDescriptorSet).layout}, + false, + true }; + m_voxelizationPipe = m_corePtr->createGraphicsPipeline(voxelizationPipeConfig); + + vkcv::DescriptorWrites voxelizationDescriptorWrites; + voxelizationDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; + voxelizationDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) }; + voxelizationDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(2, m_voxelImage.getHandle()) }; + m_corePtr->writeDescriptorSet(m_voxelizationDescriptorSet, voxelizationDescriptorWrites); + + vkcv::ShaderProgram voxelVisualisationShader = loadVoxelVisualisationShader(); + + const std::vector<vkcv::DescriptorBinding> voxelVisualisationDescriptorBindings = + { voxelVisualisationShader.getReflectedDescriptors()[0] }; + m_visualisationDescriptorSet = m_corePtr->createDescriptorSet(voxelVisualisationDescriptorBindings); + + const vkcv::AttachmentDescription voxelVisualisationColorAttachments( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + dependencies.colorBufferFormat + ); + + const vkcv::AttachmentDescription voxelVisualisationDepthAttachments( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + dependencies.depthBufferFormat + ); + + vkcv::PassConfig voxelVisualisationPassDefinition( + { voxelVisualisationColorAttachments, voxelVisualisationDepthAttachments }); + m_visualisationPass = m_corePtr->createPass(voxelVisualisationPassDefinition); + + const vkcv::PipelineConfig voxelVisualisationPipeConfig{ + voxelVisualisationShader, + 0, + 0, + m_visualisationPass, + {}, + { m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).layout }, + true, + false, + vkcv::PrimitiveTopology::PointList }; // points are extended to cubes in the geometry shader + m_visualisationPipe = m_corePtr->createGraphicsPipeline(voxelVisualisationPipeConfig); + + std::vector<uint16_t> voxelIndexData; + for (int i = 0; i < voxelCount; i++) { + voxelIndexData.push_back(i); + } + + vkcv::DescriptorWrites voxelVisualisationDescriptorWrite; + voxelVisualisationDescriptorWrite.storageImageWrites = + { vkcv::StorageImageDescriptorWrite(0, m_voxelImage.getHandle()) }; + voxelVisualisationDescriptorWrite.uniformBufferWrites = + { vkcv::UniformBufferDescriptorWrite(1, m_voxelInfoBuffer.getHandle()) }; + m_corePtr->writeDescriptorSet(m_visualisationDescriptorSet, voxelVisualisationDescriptorWrite); + + const vkcv::DescriptorSetUsage voxelizationDescriptorUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle); + + vkcv::ShaderProgram resetVoxelShader = loadVoxelResetShader(); + + m_voxelResetDescriptorSet = m_corePtr->createDescriptorSet(resetVoxelShader.getReflectedDescriptors()[0]); + m_voxelResetPipe = m_corePtr->createComputePipeline( + resetVoxelShader, + { m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).layout }); + + vkcv::DescriptorWrites resetVoxelWrites; + resetVoxelWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; + m_corePtr->writeDescriptorSet(m_voxelResetDescriptorSet, resetVoxelWrites); + + + vkcv::ShaderProgram bufferToImageShader = loadVoxelBufferToImageShader(); + + m_bufferToImageDescriptorSet = m_corePtr->createDescriptorSet(bufferToImageShader.getReflectedDescriptors()[0]); + m_bufferToImagePipe = m_corePtr->createComputePipeline( + bufferToImageShader, + { m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).layout }); + + vkcv::DescriptorWrites bufferToImageDescriptorWrites; + bufferToImageDescriptorWrites.storageBufferWrites = { vkcv::StorageBufferDescriptorWrite(0, m_voxelBuffer.getHandle()) }; + bufferToImageDescriptorWrites.storageImageWrites = { vkcv::StorageImageDescriptorWrite(1, m_voxelImage.getHandle()) }; + m_corePtr->writeDescriptorSet(m_bufferToImageDescriptorSet, bufferToImageDescriptorWrites); +} + +void Voxelization::voxelizeMeshes( + vkcv::CommandStreamHandle cmdStream, + const glm::vec3& cameraPosition, + const std::vector<vkcv::Mesh>& meshes, + const std::vector<glm::mat4>& modelMatrices, + const std::vector<vkcv::DescriptorSetHandle>& perMeshDescriptorSets) { + + VoxelizationInfo voxelizationInfo; + voxelizationInfo.extent = m_voxelExtent; + + // move voxel offset with camera in voxel sized steps + const float voxelSize = m_voxelExtent / voxelResolution; + voxelizationInfo.offset = glm::floor(cameraPosition / voxelSize) * voxelSize; + + m_voxelInfoBuffer.fill({ voxelizationInfo }); + + const float voxelizationHalfExtent = 0.5f * m_voxelExtent; + const glm::mat4 voxelizationProjection = glm::ortho( + -voxelizationHalfExtent, + voxelizationHalfExtent, + -voxelizationHalfExtent, + voxelizationHalfExtent, + -voxelizationHalfExtent, + voxelizationHalfExtent); + + const glm::mat4 voxelizationView = glm::translate(glm::mat4(1.f), -voxelizationInfo.offset); + const glm::mat4 voxelizationViewProjection = voxelizationProjection * voxelizationView; + + std::vector<std::array<glm::mat4, 2>> voxelizationMatrices; + for (const auto& m : modelMatrices) { + voxelizationMatrices.push_back({ voxelizationViewProjection * m, m }); + } + + const vkcv::PushConstantData voxelizationPushConstantData((void*)voxelizationMatrices.data(), 2 * sizeof(glm::mat4)); + + // reset voxels + const uint32_t resetVoxelGroupSize = 64; + uint32_t resetVoxelDispatchCount[3]; + resetVoxelDispatchCount[0] = glm::ceil(voxelCount / float(resetVoxelGroupSize)); + resetVoxelDispatchCount[1] = 1; + resetVoxelDispatchCount[2] = 1; + + m_corePtr->prepareImageForStorage(cmdStream, m_voxelImage.getHandle()); + m_corePtr->recordComputeDispatchToCmdStream( + cmdStream, + m_voxelResetPipe, + resetVoxelDispatchCount, + { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelResetDescriptorSet).vulkanHandle) }, + vkcv::PushConstantData(&voxelCount, sizeof(voxelCount))); + m_corePtr->recordBufferMemoryBarrier(cmdStream, m_voxelBuffer.getHandle()); + + // voxelization + std::vector<vkcv::DrawcallInfo> drawcalls; + for (int i = 0; i < meshes.size(); i++) { + drawcalls.push_back(vkcv::DrawcallInfo( + meshes[i], + { + vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_voxelizationDescriptorSet).vulkanHandle), + vkcv::DescriptorSetUsage(1, m_corePtr->getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle) + })); + } + + m_corePtr->recordDrawcallsToCmdStream( + cmdStream, + m_voxelizationPass, + m_voxelizationPipe, + voxelizationPushConstantData, + drawcalls, + { m_dummyRenderTarget.getHandle() }); + + // buffer to image + const uint32_t bufferToImageGroupSize[3] = { 4, 4, 4 }; + uint32_t bufferToImageDispatchCount[3]; + for (int i = 0; i < 3; i++) { + bufferToImageDispatchCount[i] = glm::ceil(voxelResolution / float(bufferToImageGroupSize[i])); + } + + m_corePtr->recordComputeDispatchToCmdStream( + cmdStream, + m_bufferToImagePipe, + bufferToImageDispatchCount, + { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_bufferToImageDescriptorSet).vulkanHandle) }, + vkcv::PushConstantData(nullptr, 0)); + + m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle()); +} + +void Voxelization::renderVoxelVisualisation( + vkcv::CommandStreamHandle cmdStream, + const glm::mat4& viewProjectin, + const std::vector<vkcv::ImageHandle>& renderTargets) { + + const vkcv::PushConstantData voxelVisualisationPushConstantData((void*)&viewProjectin, sizeof(glm::mat4)); + + const auto drawcall = vkcv::DrawcallInfo( + vkcv::Mesh({}, nullptr, voxelCount), + { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_visualisationDescriptorSet).vulkanHandle) }); + + m_corePtr->recordDrawcallsToCmdStream( + cmdStream, + m_visualisationPass, + m_visualisationPipe, + voxelVisualisationPushConstantData, + { drawcall }, + renderTargets); +} \ No newline at end of file diff --git a/projects/voxelization/src/Voxelization.hpp b/projects/voxelization/src/Voxelization.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f9b96998b39e24a3481d130efa68ebaa813b8256 --- /dev/null +++ b/projects/voxelization/src/Voxelization.hpp @@ -0,0 +1,59 @@ +#pragma once +#include <vkcv/Core.hpp> +#include <glm/glm.hpp> + +class Voxelization{ +public: + struct Dependencies { + vkcv::VertexLayout vertexLayout; + vk::Format colorBufferFormat; + vk::Format depthBufferFormat; + }; + Voxelization(vkcv::Core* corePtr, const Dependencies& dependencies); + + void voxelizeMeshes( + vkcv::CommandStreamHandle cmdStream, + const glm::vec3& cameraPosition, + const std::vector<vkcv::Mesh>& meshes, + const std::vector<glm::mat4>& modelMatrices, + const std::vector<vkcv::DescriptorSetHandle>& perMeshDescriptorSets); + + void renderVoxelVisualisation( + vkcv::CommandStreamHandle cmdStream, + const glm::mat4& viewProjectin, + const std::vector<vkcv::ImageHandle>& renderTargets); + +private: + vkcv::Core* m_corePtr; + + struct VoxelBufferContent{ + uint32_t isFilled; + }; + + vkcv::Image m_voxelImage; + vkcv::Buffer<VoxelBufferContent> m_voxelBuffer; + + vkcv::Image m_dummyRenderTarget; + vkcv::PassHandle m_voxelizationPass; + vkcv::PipelineHandle m_voxelizationPipe; + vkcv::DescriptorSetHandle m_voxelizationDescriptorSet; + + vkcv::PipelineHandle m_voxelResetPipe; + vkcv::DescriptorSetHandle m_voxelResetDescriptorSet; + + vkcv::PipelineHandle m_bufferToImagePipe; + vkcv::DescriptorSetHandle m_bufferToImageDescriptorSet; + + vkcv::PassHandle m_visualisationPass; + vkcv::PipelineHandle m_visualisationPipe; + + vkcv::DescriptorSetHandle m_visualisationDescriptorSet; + + struct VoxelizationInfo { + glm::vec3 offset; + float extent; + }; + vkcv::Buffer<VoxelizationInfo> m_voxelInfoBuffer; + + const float m_voxelExtent = 20.f; +}; \ No newline at end of file diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81d99f8af37722735742c697171219e012f6b339 --- /dev/null +++ b/projects/voxelization/src/main.cpp @@ -0,0 +1,441 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <vkcv/Logger.hpp> +#include "Voxelization.hpp" +#include <glm/glm.hpp> + +int main(int argc, const char** argv) { + const char* applicationName = "Voxelization"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + true + ); + + vkcv::camera::CameraManager cameraManager(window); + uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex).setPosition(glm::vec3(0.f, 0.f, 3.f)); + cameraManager.getCamera(camIndex).setNearFar(0.1f, 30.0f); + cameraManager.getCamera(camIndex).setYaw(180.0f); + + cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f); + + window.initEvents(); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + {}, + { "VK_KHR_swapchain" } + ); + + vkcv::asset::Scene mesh; + + const char* path = argc > 1 ? argv[1] : "resources/Sponza/Sponza.gltf"; + vkcv::asset::Scene scene; + int result = vkcv::asset::loadScene(path, scene); + + if (result == 1) { + std::cout << "Scene loading successful!" << std::endl; + } + else { + std::cout << "Scene loading failed: " << result << std::endl; + return 1; + } + + // build index and vertex buffers + assert(!scene.vertexGroups.empty()); + std::vector<std::vector<uint8_t>> vBuffers; + std::vector<std::vector<uint8_t>> iBuffers; + + std::vector<vkcv::VertexBufferBinding> vBufferBindings; + std::vector<std::vector<vkcv::VertexBufferBinding>> vertexBufferBindings; + std::vector<vkcv::asset::VertexAttribute> vAttributes; + + for (int i = 0; i < scene.vertexGroups.size(); i++) { + + vBuffers.push_back(scene.vertexGroups[i].vertexBuffer.data); + iBuffers.push_back(scene.vertexGroups[i].indexBuffer.data); + + auto& attributes = scene.vertexGroups[i].vertexBuffer.attributes; + + std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + } + + std::vector<vkcv::Buffer<uint8_t>> vertexBuffers; + for (const vkcv::asset::VertexGroup& group : scene.vertexGroups) { + vertexBuffers.push_back(core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + group.vertexBuffer.data.size())); + vertexBuffers.back().fill(group.vertexBuffer.data); + } + + std::vector<vkcv::Buffer<uint8_t>> indexBuffers; + for (const auto& dataBuffer : iBuffers) { + indexBuffers.push_back(core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + dataBuffer.size())); + indexBuffers.back().fill(dataBuffer); + } + + int vertexBufferIndex = 0; + for (const auto& vertexGroup : scene.vertexGroups) { + for (const auto& attribute : vertexGroup.vertexBuffer.attributes) { + vAttributes.push_back(attribute); + vBufferBindings.push_back(vkcv::VertexBufferBinding(attribute.offset, vertexBuffers[vertexBufferIndex].getVulkanHandle())); + } + vertexBufferBindings.push_back(vBufferBindings); + vBufferBindings.clear(); + vertexBufferIndex++; + } + + const vk::Format colorBufferFormat = vk::Format::eB10G11R11UfloatPack32; + const vkcv::AttachmentDescription color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + colorBufferFormat + ); + + const vk::Format depthBufferFormat = vk::Format::eD32Sfloat; + const vkcv::AttachmentDescription depth_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + depthBufferFormat + ); + + vkcv::PassConfig forwardPassDefinition({ color_attachment, depth_attachment }); + vkcv::PassHandle forwardPass = core.createPass(forwardPassDefinition); + + vkcv::shader::GLSLCompiler compiler; + + vkcv::ShaderProgram forwardProgram; + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/shader.vert"), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + forwardProgram.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/shader.frag"), + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + forwardProgram.addShader(shaderStage, path); + }); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = forwardProgram.getVertexAttachments(); + + std::vector<vkcv::VertexBinding> vertexBindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + vertexBindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + const vkcv::VertexLayout vertexLayout (vertexBindings); + + // shadow map + vkcv::SamplerHandle shadowSampler = core.createSampler( + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerMipmapMode::NEAREST, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE + ); + const vk::Format shadowMapFormat = vk::Format::eD16Unorm; + const uint32_t shadowMapResolution = 1024; + const vkcv::Image shadowMap = core.createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1); + + // light info buffer + struct LightInfo { + glm::vec3 direction; + float padding; + glm::mat4 lightMatrix; + }; + LightInfo lightInfo; + vkcv::Buffer lightBuffer = core.createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3)); + + vkcv::DescriptorSetHandle forwardShadingDescriptorSet = + core.createDescriptorSet({ forwardProgram.getReflectedDescriptors()[0] }); + + vkcv::DescriptorWrites forwardDescriptorWrites; + forwardDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(0, lightBuffer.getHandle()) }; + forwardDescriptorWrites.sampledImageWrites = { vkcv::SampledImageDescriptorWrite(1, shadowMap.getHandle()) }; + forwardDescriptorWrites.samplerWrites = { vkcv::SamplerDescriptorWrite(2, shadowSampler) }; + core.writeDescriptorSet(forwardShadingDescriptorSet, forwardDescriptorWrites); + + vkcv::SamplerHandle colorSampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + // prepare per mesh descriptor sets + std::vector<vkcv::DescriptorSetHandle> perMeshDescriptorSets; + std::vector<vkcv::Image> sceneImages; + for (const auto& vertexGroup : scene.vertexGroups) { + perMeshDescriptorSets.push_back(core.createDescriptorSet(forwardProgram.getReflectedDescriptors()[1])); + + const auto& material = scene.materials[vertexGroup.materialIndex]; + + int baseColorIndex = material.baseColor; + if (baseColorIndex < 0) { + vkcv_log(vkcv::LogLevel::WARNING, "Material lacks base color"); + baseColorIndex = 0; + } + + vkcv::asset::Texture& sceneTexture = scene.textures[baseColorIndex]; + + sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Srgb, sceneTexture.w, sceneTexture.h)); + sceneImages.back().fill(sceneTexture.data.data()); + + vkcv::DescriptorWrites setWrites; + setWrites.sampledImageWrites = { + vkcv::SampledImageDescriptorWrite(0, sceneImages.back().getHandle()) + }; + setWrites.samplerWrites = { + vkcv::SamplerDescriptorWrite(1, colorSampler), + }; + core.writeDescriptorSet(perMeshDescriptorSets.back(), setWrites); + } + + const vkcv::PipelineConfig forwardPipelineConfig { + forwardProgram, + windowWidth, + windowHeight, + forwardPass, + vertexLayout, + { core.getDescriptorSet(forwardShadingDescriptorSet).layout, + core.getDescriptorSet(perMeshDescriptorSets[0]).layout }, + true + }; + + vkcv::PipelineHandle forwardPipeline = core.createGraphicsPipeline(forwardPipelineConfig); + + if (!forwardPipeline) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ImageHandle depthBuffer = core.createImage(depthBufferFormat, windowWidth, windowHeight).getHandle(); + vkcv::ImageHandle colorBuffer = core.createImage(colorBufferFormat, windowWidth, windowHeight, 1, true, true).getHandle(); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + vkcv::ShaderProgram shadowShader; + compiler.compile(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow.vert", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shadowShader.addShader(shaderStage, path); + }); + compiler.compile(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow.frag", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + shadowShader.addShader(shaderStage, path); + }); + + const std::vector<vkcv::AttachmentDescription> shadowAttachments = { + vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat) + }; + const vkcv::PassConfig shadowPassConfig(shadowAttachments); + const vkcv::PassHandle shadowPass = core.createPass(shadowPassConfig); + const vkcv::PipelineConfig shadowPipeConfig{ + shadowShader, + shadowMapResolution, + shadowMapResolution, + shadowPass, + vertexLayout, + {}, + false + }; + const vkcv::PipelineHandle shadowPipe = core.createGraphicsPipeline(shadowPipeConfig); + + std::vector<std::array<glm::mat4, 2>> mainPassMatrices; + std::vector<glm::mat4> mvpLight; + + bool renderVoxelVis = false; + window.e_key.add([&renderVoxelVis](int key ,int scancode, int action, int mods) { + if (key == GLFW_KEY_V && action == GLFW_PRESS) { + renderVoxelVis = !renderVoxelVis; + } + }); + + // gamma correction compute shader + vkcv::ShaderProgram gammaCorrectionProgram; + compiler.compile(vkcv::ShaderStage::COMPUTE, "resources/shaders/gammaCorrection.comp", + [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + gammaCorrectionProgram.addShader(shaderStage, path); + }); + vkcv::DescriptorSetHandle gammaCorrectionDescriptorSet = core.createDescriptorSet(gammaCorrectionProgram.getReflectedDescriptors()[0]); + vkcv::PipelineHandle gammaCorrectionPipeline = core.createComputePipeline(gammaCorrectionProgram, + { core.getDescriptorSet(gammaCorrectionDescriptorSet).layout }); + + // model matrices per mesh + std::vector<glm::mat4> modelMatrices; + modelMatrices.resize(scene.vertexGroups.size(), glm::mat4(1.f)); + for (const auto& mesh : scene.meshes) { + const glm::mat4 m = *reinterpret_cast<const glm::mat4*>(&mesh.modelMatrix[0]); + for (const auto& vertexGroupIndex : mesh.vertexGroups) { + modelMatrices[vertexGroupIndex] = m; + } + } + + // prepare drawcalls + std::vector<vkcv::Mesh> meshes; + for (int i = 0; i < scene.vertexGroups.size(); i++) { + vkcv::Mesh mesh( + vertexBufferBindings[i], + indexBuffers[i].getVulkanHandle(), + scene.vertexGroups[i].numIndices); + meshes.push_back(mesh); + } + + std::vector<vkcv::DrawcallInfo> drawcalls; + std::vector<vkcv::DrawcallInfo> shadowDrawcalls; + for (int i = 0; i < meshes.size(); i++) { + + drawcalls.push_back(vkcv::DrawcallInfo(meshes[i], { + vkcv::DescriptorSetUsage(0, core.getDescriptorSet(forwardShadingDescriptorSet).vulkanHandle), + vkcv::DescriptorSetUsage(1, core.getDescriptorSet(perMeshDescriptorSets[i]).vulkanHandle) })); + shadowDrawcalls.push_back(vkcv::DrawcallInfo(meshes[i], {})); + } + + Voxelization::Dependencies voxelDependencies; + voxelDependencies.colorBufferFormat = colorBufferFormat; + voxelDependencies.depthBufferFormat = depthBufferFormat; + voxelDependencies.vertexLayout = vertexLayout; + Voxelization voxelization(&core, voxelDependencies); + + auto start = std::chrono::system_clock::now(); + const auto appStartTime = start; + while (window.isWindowOpen()) { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight)) { + continue; + } + + if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { + depthBuffer = core.createImage(depthBufferFormat, swapchainWidth, swapchainHeight).getHandle(); + colorBuffer = core.createImage(colorBufferFormat, swapchainWidth, swapchainHeight, 1, true, true).getHandle(); + + windowWidth = swapchainWidth; + windowHeight = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + + // update descriptor sets which use swapchain image + vkcv::DescriptorWrites gammaCorrectionDescriptorWrites; + gammaCorrectionDescriptorWrites.storageImageWrites = { + vkcv::StorageImageDescriptorWrite(0, colorBuffer), + vkcv::StorageImageDescriptorWrite(1, swapchainInput) }; + core.writeDescriptorSet(gammaCorrectionDescriptorSet, gammaCorrectionDescriptorWrites); + + start = end; + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - appStartTime); + + const float sunTheta = 0.001f * static_cast<float>(duration.count()); + lightInfo.direction = glm::normalize(glm::vec3(std::cos(sunTheta), 1, std::sin(sunTheta))); + + const float shadowProjectionSize = 20.f; + glm::mat4 projectionLight = glm::ortho( + -shadowProjectionSize, + shadowProjectionSize, + -shadowProjectionSize, + shadowProjectionSize, + -shadowProjectionSize, + shadowProjectionSize); + + glm::mat4 vulkanCorrectionMatrix(1.f); + vulkanCorrectionMatrix[2][2] = 0.5; + vulkanCorrectionMatrix[3][2] = 0.5; + projectionLight = vulkanCorrectionMatrix * projectionLight; + + const glm::mat4 viewLight = glm::lookAt(glm::vec3(0), -lightInfo.direction, glm::vec3(0, -1, 0)); + + lightInfo.lightMatrix = projectionLight * viewLight; + lightBuffer.fill({ lightInfo }); + + const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP(); + + mainPassMatrices.clear(); + mvpLight.clear(); + for (const auto& m : modelMatrices) { + mainPassMatrices.push_back({ viewProjectionCamera * m, m }); + mvpLight.push_back(lightInfo.lightMatrix * m); + } + + vkcv::PushConstantData pushConstantData((void*)mainPassMatrices.data(), 2 * sizeof(glm::mat4)); + const std::vector<vkcv::ImageHandle> renderTargets = { colorBuffer, depthBuffer }; + + const vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4)); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + // shadow map + core.recordDrawcallsToCmdStream( + cmdStream, + shadowPass, + shadowPipe, + shadowPushConstantData, + shadowDrawcalls, + { shadowMap.getHandle() }); + core.prepareImageForSampling(cmdStream, shadowMap.getHandle()); + + voxelization.voxelizeMeshes( + cmdStream, + cameraManager.getActiveCamera().getPosition(), + meshes, + modelMatrices, + perMeshDescriptorSets); + + // main pass + core.recordDrawcallsToCmdStream( + cmdStream, + forwardPass, + forwardPipeline, + pushConstantData, + drawcalls, + renderTargets); + + if (renderVoxelVis) { + voxelization.renderVoxelVisualisation(cmdStream, viewProjectionCamera, renderTargets); + } + + const uint32_t gammaCorrectionLocalGroupSize = 8; + const uint32_t gammaCorrectionDispatchCount[3] = { + static_cast<uint32_t>(glm::ceil(windowWidth / static_cast<float>(gammaCorrectionLocalGroupSize))), + static_cast<uint32_t>(glm::ceil(windowHeight / static_cast<float>(gammaCorrectionLocalGroupSize))), + 1 + }; + + core.prepareImageForStorage(cmdStream, swapchainInput); + core.prepareImageForStorage(cmdStream, colorBuffer); + + core.recordComputeDispatchToCmdStream( + cmdStream, + gammaCorrectionPipeline, + gammaCorrectionDispatchCount, + { vkcv::DescriptorSetUsage(0, core.getDescriptorSet(gammaCorrectionDescriptorSet).vulkanHandle) }, + vkcv::PushConstantData(nullptr, 0)); + + // present and end + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + core.endFrame(); + } + + return 0; +} diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp index 6d494c4ec90726d46039007607464378624f1c75..4df411c193acffa42401e4f5932d97f531cac9c9 100644 --- a/src/vkcv/BufferManager.cpp +++ b/src/vkcv/BufferManager.cpp @@ -5,6 +5,7 @@ #include "vkcv/BufferManager.hpp" #include "vkcv/Core.hpp" +#include <vkcv/Logger.hpp> namespace vkcv { @@ -335,4 +336,33 @@ namespace vkcv { } } + void BufferManager ::recordBufferMemoryBarrier(const BufferHandle& handle, vk::CommandBuffer cmdBuffer) { + + const uint64_t id = handle.getId(); + + if (id >= m_buffers.size()) { + vkcv_log(vkcv::LogLevel::ERROR, "Invalid buffer handle"); + return; + } + + auto& buffer = m_buffers[id]; + + vk::BufferMemoryBarrier memoryBarrier( + vk::AccessFlagBits::eMemoryWrite, + vk::AccessFlagBits::eMemoryRead, + 0, + 0, + buffer.m_handle, + 0, + buffer.m_size); + + cmdBuffer.pipelineBarrier( + vk::PipelineStageFlagBits::eTopOfPipe, + vk::PipelineStageFlagBits::eBottomOfPipe, + {}, + nullptr, + memoryBarrier, + nullptr); + } + } diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index b53a1a2c2db1008e7c69c880ef1c5a608d879021..ac133d1affc81702ee1a19b3f66810e606bec58d 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -275,7 +275,13 @@ namespace vkcv deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size()); deviceCreateInfo.ppEnabledLayerNames = validationLayers.data(); #endif - + + // FIXME: check if device feature is supported + vk::PhysicalDeviceFeatures deviceFeatures; + deviceFeatures.fragmentStoresAndAtomics = true; + deviceFeatures.geometryShader = true; + deviceCreateInfo.pEnabledFeatures = &deviceFeatures; + // Ablauf // qCreateInfos erstellen --> braucht das Device // device erstellen diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 49707d4cffc18719d8fbb18a9e632e12ba679c2e..fd2c595b4305740e801e8d3d50af74521fc3418c 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -37,8 +37,7 @@ namespace vkcv Swapchain swapChain = Swapchain::create(window, context); - std::vector<vk::ImageView> imageViews; - imageViews = createImageViews( context, swapChain); + std::vector<vk::ImageView> swapchainImageViews = createSwapchainImageViews( context, swapChain); const auto& queueManager = context.getQueueManager(); @@ -47,7 +46,7 @@ namespace vkcv const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet); const auto defaultSyncResources = createSyncResources(context.getDevice()); - return Core(std::move(context) , window, swapChain, imageViews, commandResources, defaultSyncResources); + return Core(std::move(context) , window, swapChain, swapchainImageViews, commandResources, defaultSyncResources); } const Context &Core::getContext() const @@ -59,12 +58,11 @@ namespace vkcv return m_swapchain; } - Core::Core(Context &&context, Window &window, const Swapchain& swapChain, std::vector<vk::ImageView> imageViews, + Core::Core(Context &&context, Window &window, const Swapchain& swapChain, std::vector<vk::ImageView> swapchainImageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : m_Context(std::move(context)), m_window(window), m_swapchain(swapChain), - m_swapchainImageViews(imageViews), m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)}, m_PipelineManager{std::make_unique<PipelineManager>(m_Context.m_Device)}, m_DescriptorManager(std::make_unique<DescriptorManager>(m_Context.m_Device)), @@ -85,17 +83,19 @@ namespace vkcv m_swapchain.signalSwapchainRecreation(); }); - m_swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); - m_swapchainImageLayouts.resize(m_swapchainImages.size(), vk::ImageLayout::eUndefined); + const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); + m_ImageManager->setSwapchainImages( + swapchainImages, + swapchainImageViews, + swapChain.getExtent().width, + swapChain.getExtent().height, + swapChain.getFormat()); } Core::~Core() noexcept { m_window.e_resize.remove(e_resizeHandle); m_Context.getDevice().waitIdle(); - for (auto image : m_swapchainImageViews) { - m_Context.m_Device.destroyImageView(image); - } destroyCommandResources(m_Context.getDevice(), m_CommandResources); destroySyncResources(m_Context.getDevice(), m_SyncResources); @@ -151,16 +151,12 @@ namespace vkcv bool Core::beginFrame(uint32_t& width, uint32_t& height) { if (m_swapchain.shouldUpdateSwapchain()) { m_Context.getDevice().waitIdle(); - - for (auto image : m_swapchainImageViews) - m_Context.m_Device.destroyImageView(image); - + m_swapchain.updateSwapchain(m_Context, m_window); - m_swapchainImageViews = createImageViews(m_Context, m_swapchain); - m_swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); + const auto swapchainViews = createSwapchainImageViews(m_Context, m_swapchain); + const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); - m_swapchainImageLayouts.clear(); - m_swapchainImageLayouts.resize(m_swapchainImages.size(), vk::ImageLayout::eUndefined); + m_ImageManager->setSwapchainImages(swapchainImages, swapchainViews, width, height, m_swapchain.getFormat()); } if (acquireSwapchainImage() != Result::SUCCESS) { @@ -176,6 +172,8 @@ namespace vkcv width = extent.width; height = extent.height; + m_ImageManager->setCurrentSwapchainImageIndex(m_currentSwapchainImageIndex); + return (m_currentSwapchainImageIndex != std::numeric_limits<uint32_t>::max()); } @@ -218,23 +216,16 @@ namespace vkcv const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height)); - const vk::ImageView swapchainImageView = m_swapchainImageViews[m_currentSwapchainImageIndex]; - std::vector<vk::ImageView> attachmentsViews; for (const ImageHandle handle : renderTargets) { vk::ImageView targetHandle; const auto cmdBuffer = m_CommandStreamManager->getStreamCommandBuffer(cmdStreamHandle); - if (handle.isSwapchainImage()) { - recordSwapchainImageLayoutTransition(cmdBuffer, vk::ImageLayout::eColorAttachmentOptimal); - targetHandle = m_swapchainImageViews[m_currentSwapchainImageIndex]; - } - else { - targetHandle = m_ImageManager->getVulkanImageView(handle); - const bool isDepthImage = isDepthFormat(m_ImageManager->getImageFormat(handle)); - const vk::ImageLayout targetLayout = - isDepthFormat ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal; - m_ImageManager->recordImageLayoutTransition(handle, targetLayout, cmdBuffer); - } + + targetHandle = m_ImageManager->getVulkanImageView(handle); + const bool isDepthImage = isDepthFormat(m_ImageManager->getImageFormat(handle)); + const vk::ImageLayout targetLayout = + isDepthImage ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal; + m_ImageManager->recordImageLayoutTransition(handle, targetLayout, cmdBuffer); attachmentsViews.push_back(targetHandle); } @@ -451,9 +442,9 @@ namespace vkcv return m_SamplerManager->createSampler(magFilter, minFilter, mipmapMode, addressMode); } - Image Core::createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth) + Image Core::createImage(vk::Format format, uint32_t width, uint32_t height, uint32_t depth, bool supportStorage, bool supportColorAttachment) { - return Image::create(m_ImageManager.get(), format, width, height, depth); + return Image::create(m_ImageManager.get(), format, width, height, depth, supportStorage, supportColorAttachment); } DescriptorSetHandle Core::createDescriptorSet(const std::vector<DescriptorBinding>& bindings) @@ -463,7 +454,7 @@ namespace vkcv void Core::writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites &writes) { m_DescriptorManager->writeDescriptorSet( - handle, + handle, writes, *m_ImageManager, *m_BufferManager, @@ -474,7 +465,7 @@ namespace vkcv return m_DescriptorManager->getDescriptorSet(handle); } - std::vector<vk::ImageView> Core::createImageViews( Context &context, Swapchain& swapChain){ + std::vector<vk::ImageView> Core::createSwapchainImageViews( Context &context, Swapchain& swapChain){ std::vector<vk::ImageView> imageViews; std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain()); imageViews.reserve( swapChainImages.size() ); @@ -502,20 +493,11 @@ namespace vkcv return imageViews; } - void Core::recordSwapchainImageLayoutTransition(vk::CommandBuffer cmdBuffer, vk::ImageLayout newLayout) { - auto& imageLayout = m_swapchainImageLayouts[m_currentSwapchainImageIndex]; - const auto transitionBarrier = createSwapchainImageLayoutTransitionBarrier( - m_swapchainImages[m_currentSwapchainImageIndex], - imageLayout, - newLayout); - recordImageBarrier(cmdBuffer, transitionBarrier); - imageLayout = newLayout; - } - - void Core::prepareSwapchainImageForPresent(const CommandStreamHandle handle) { - m_CommandStreamManager->recordCommandsToStream(handle, [&](vk::CommandBuffer cmdBuffer) { - recordSwapchainImageLayoutTransition(cmdBuffer, vk::ImageLayout::ePresentSrcKHR); - }); + void Core::prepareSwapchainImageForPresent(const CommandStreamHandle cmdStream) { + auto swapchainHandle = ImageHandle::createSwapchainImageHandle(); + recordCommandsToStream(cmdStream, [swapchainHandle, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageLayoutTransition(swapchainHandle, vk::ImageLayout::ePresentSrcKHR, cmdBuffer); + }, nullptr); } void Core::prepareImageForSampling(const CommandStreamHandle cmdStream, const ImageHandle image) { @@ -523,9 +505,27 @@ namespace vkcv m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer); }, nullptr); } + + void Core::prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image) { + recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eGeneral, cmdBuffer); + }, nullptr); + } + + void Core::recordImageMemoryBarrier(const CommandStreamHandle cmdStream, const ImageHandle image) { + recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageMemoryBarrier(image, cmdBuffer); + }, nullptr); + } + + void Core::recordBufferMemoryBarrier(const CommandStreamHandle cmdStream, const BufferHandle buffer) { + recordCommandsToStream(cmdStream, [buffer, this](const vk::CommandBuffer cmdBuffer) { + m_BufferManager->recordBufferMemoryBarrier(buffer, cmdBuffer); + }, nullptr); + } const vk::ImageView& Core::getSwapchainImageView() const { - return m_swapchainImageViews[m_currentSwapchainImageIndex]; + return m_ImageManager->getVulkanImageView(vkcv::ImageHandle::createSwapchainImageHandle()); } } diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp index 85b6eeb5fa413223b7b7f10f77b868252912041b..df7b7bbcb3fe278622cd160593eb750db00ec7b1 100644 --- a/src/vkcv/DrawcallRecording.cpp +++ b/src/vkcv/DrawcallRecording.cpp @@ -23,8 +23,6 @@ namespace vkcv { nullptr); } - cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size - const size_t drawcallPushConstantOffset = drawcallIndex * pushConstantData.sizePerDrawcall; // char* cast because void* does not support pointer arithmetic const void* drawcallPushConstantData = drawcallPushConstantOffset + (char*)pushConstantData.data; @@ -36,6 +34,12 @@ namespace vkcv { pushConstantData.sizePerDrawcall, drawcallPushConstantData); - cmdBuffer.drawIndexed(drawcall.mesh.indexCount, 1, 0, 0, {}); + if (drawcall.mesh.indexBuffer) { + cmdBuffer.bindIndexBuffer(drawcall.mesh.indexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size + cmdBuffer.drawIndexed(drawcall.mesh.indexCount, 1, 0, 0, {}); + } + else { + cmdBuffer.draw(drawcall.mesh.indexCount, 1, 0, 0, {}); + } } } \ No newline at end of file diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp index f861daeb1cd7de9697e2f649de444666b8b0e63c..9f7fdadc7400fd3e63061f1e40cd494db63a7869 100644 --- a/src/vkcv/Image.cpp +++ b/src/vkcv/Image.cpp @@ -19,9 +19,9 @@ namespace vkcv{ } } - Image Image::create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth) + Image Image::create(ImageManager* manager, vk::Format format, uint32_t width, uint32_t height, uint32_t depth, bool supportStorage, bool supportColorAttachment) { - return Image(manager, manager->createImage(width, height, depth, format)); + return Image(manager, manager->createImage(width, height, depth, format, supportStorage, supportColorAttachment)); } vk::Format Image::getFormat() const { diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 1e3d19d02d7e86546d142bb64440364407e81824..fff98dc5b56d0ad085c6ebc68acf7230223d9cd1 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -69,6 +69,8 @@ namespace vkcv { for (uint64_t id = 0; id < m_images.size(); id++) { destroyImageById(id); } + for (const auto swapchainImage : m_swapchainImages) + m_core->getContext().getDevice().destroy(swapchainImage.m_view); } bool isDepthImageFormat(vk::Format format) { @@ -81,7 +83,7 @@ namespace vkcv { } } - ImageHandle ImageManager::createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format) + ImageHandle ImageManager::createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format, bool supportStorage, bool supportColorAttachment) { const vk::PhysicalDevice& physicalDevice = m_core->getContext().getPhysicalDevice(); @@ -91,6 +93,12 @@ namespace vkcv { vk::ImageUsageFlags imageUsageFlags = ( vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst ); + if (supportStorage) { + imageUsageFlags |= vk::ImageUsageFlagBits::eStorage; + } + if (supportColorAttachment) { + imageUsageFlags |= vk::ImageUsageFlagBits::eColorAttachment; + } const bool isDepthFormat = isDepthImageFormat(format); @@ -204,8 +212,12 @@ namespace vkcv { } vk::Image ImageManager::getVulkanImage(const ImageHandle &handle) const { + + if (handle.isSwapchainImage()) { + m_swapchainImages[m_currentSwapchainInputImage].m_handle; + } + const uint64_t id = handle.getId(); - if (id >= m_images.size()) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return nullptr; @@ -217,8 +229,13 @@ namespace vkcv { } vk::DeviceMemory ImageManager::getVulkanDeviceMemory(const ImageHandle &handle) const { + + if (handle.isSwapchainImage()) { + vkcv_log(LogLevel::ERROR, "Swapchain image has no memory"); + return nullptr; + } + const uint64_t id = handle.getId(); - if (id >= m_images.size()) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return nullptr; @@ -230,27 +247,31 @@ namespace vkcv { } vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle) const { - const uint64_t id = handle.getId(); + if (handle.isSwapchainImage()) { + return m_swapchainImages[m_currentSwapchainInputImage].m_view; + } + + const uint64_t id = handle.getId(); if (id >= m_images.size()) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return nullptr; } - auto& image = m_images[id]; - - return image.m_view; + return m_images[id].m_view; } void ImageManager::switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout) { - const uint64_t id = handle.getId(); + uint64_t id = handle.getId(); - if (id >= m_images.size()) { + const bool isSwapchainImage = handle.isSwapchainImage(); + + if (id >= m_images.size() && !isSwapchainImage) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return; } - auto& image = m_images[id]; + auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; const auto transitionBarrier = createImageLayoutTransitionBarrier(image, newLayout); SubmitInfo submitInfo; @@ -279,22 +300,57 @@ namespace vkcv { vk::CommandBuffer cmdBuffer) { const uint64_t id = handle.getId(); + const bool isSwapchainImage = handle.isSwapchainImage(); - if (id >= m_images.size()) { + if (id >= m_images.size() && !isSwapchainImage) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return; } - auto& image = m_images[id]; + auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; const auto transitionBarrier = createImageLayoutTransitionBarrier(image, newLayout); recordImageBarrier(cmdBuffer, transitionBarrier); image.m_layout = newLayout; } + + void ImageManager::recordImageMemoryBarrier( + const ImageHandle& handle, + vk::CommandBuffer cmdBuffer) { + + const uint64_t id = handle.getId(); + const bool isSwapchainImage = handle.isSwapchainImage(); + + if (id >= m_images.size() && !isSwapchainImage) { + std::cerr << "Error: ImageManager::recordImageMemoryBarrier invalid handle" << std::endl; + return; + } + + auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; + const auto transitionBarrier = createImageLayoutTransitionBarrier(image, image.m_layout); + recordImageBarrier(cmdBuffer, transitionBarrier); + } + + constexpr uint32_t getChannelsByFormat(vk::Format format) { + switch (format) { + case vk::Format::eR8Unorm: + return 1; + case vk::Format::eR8G8B8A8Srgb: + return 4; + default: + std::cerr << "Check format instead of guessing, please!" << std::endl; + return 4; + } + } void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size) { const uint64_t id = handle.getId(); + if (handle.isSwapchainImage()) { + vkcv_log(LogLevel::ERROR, "Swapchain image cannot be filled"); + return; + } + if (id >= m_images.size()) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return; @@ -306,7 +362,7 @@ namespace vkcv { handle, vk::ImageLayout::eTransferDstOptimal); - uint32_t channels = 4; // TODO: check image.m_format + uint32_t channels = getChannelsByFormat(image.m_format); const size_t image_size = ( image.m_width * image.m_height * image.m_depth * channels ); @@ -368,39 +424,42 @@ namespace vkcv { uint32_t ImageManager::getImageWidth(const ImageHandle &handle) const { const uint64_t id = handle.getId(); - - if (id >= m_images.size()) { + const bool isSwapchainImage = handle.isSwapchainImage(); + + if (id >= m_images.size() && !isSwapchainImage) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return 0; } - auto& image = m_images[id]; + auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; return image.m_width; } uint32_t ImageManager::getImageHeight(const ImageHandle &handle) const { const uint64_t id = handle.getId(); + const bool isSwapchainImage = handle.isSwapchainImage(); - if (id >= m_images.size()) { + if (id >= m_images.size() && !isSwapchainImage) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return 0; } - auto& image = m_images[id]; + auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; return image.m_height; } uint32_t ImageManager::getImageDepth(const ImageHandle &handle) const { const uint64_t id = handle.getId(); - - if (id >= m_images.size()) { + const bool isSwapchainImage = handle.isSwapchainImage(); + + if (id >= m_images.size() && !isSwapchainImage) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return 0; } - auto& image = m_images[id]; + auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; return image.m_depth; } @@ -435,13 +494,32 @@ namespace vkcv { vk::Format ImageManager::getImageFormat(const ImageHandle& handle) const { const uint64_t id = handle.getId(); + const bool isSwapchainFormat = handle.isSwapchainImage(); - if (id >= m_images.size()) { + if (id >= m_images.size() && !isSwapchainFormat) { vkcv_log(LogLevel::ERROR, "Invalid handle"); return vk::Format::eUndefined; } - return m_images[id].m_format; + return isSwapchainFormat ? m_swapchainImages[m_currentSwapchainInputImage].m_format : m_images[id].m_format; + } + + void ImageManager::setCurrentSwapchainImageIndex(int index) { + m_currentSwapchainInputImage = index; + } + + void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, + uint32_t width, uint32_t height, vk::Format format) { + + // destroy old views + for (auto image : m_swapchainImages) + m_core->getContext().getDevice().destroyImageView(image.m_view); + + assert(images.size() == views.size()); + m_swapchainImages.clear(); + for (int i = 0; i < images.size(); i++) { + m_swapchainImages.push_back(Image(images[i], nullptr, views[i], width, height, 1, format, 1, 1)); + } } } \ No newline at end of file diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index b9fccb25ec16bc1fd9569ab1a94627bd7ff06b18..7bb4cc7ef7951a8677c19f589bd7948dbcedb25d 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -41,6 +41,8 @@ namespace vkcv { vk::Format format, uint32_t layers, uint32_t levels); + + Image(); }; private: @@ -48,6 +50,8 @@ namespace vkcv { BufferManager& m_bufferManager; std::vector<Image> m_images; + std::vector<Image> m_swapchainImages; + int m_currentSwapchainInputImage; ImageManager(BufferManager& bufferManager) noexcept; @@ -67,7 +71,7 @@ namespace vkcv { ImageManager& operator=(ImageManager&& other) = delete; ImageManager& operator=(const ImageManager& other) = delete; - ImageHandle createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format); + ImageHandle createImage(uint32_t width, uint32_t height, uint32_t depth, vk::Format format, bool supportStorage, bool supportColorAttachment); ImageHandle createSwapchainImage(); @@ -86,6 +90,10 @@ namespace vkcv { vk::ImageLayout newLayout, vk::CommandBuffer cmdBuffer); + void recordImageMemoryBarrier( + const ImageHandle& handle, + vk::CommandBuffer cmdBuffer); + void fillImage(const ImageHandle& handle, void* data, size_t size); [[nodiscard]] @@ -99,5 +107,10 @@ namespace vkcv { [[nodiscard]] vk::Format getImageFormat(const ImageHandle& handle) const; + + void setCurrentSwapchainImageIndex(int index); + void setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, + uint32_t width, uint32_t height, vk::Format format); + }; } \ No newline at end of file diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 949e5b9f713f3cac72d67b8a22cae46fc12aef0d..df36442efc2992bf16b6e82245ef9753dad95e5d 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -42,6 +42,15 @@ namespace vkcv } } + vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) { + switch (topology) { + case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList; + case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList; + case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList; + default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList; + } + } + PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager) { const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle); @@ -124,9 +133,9 @@ namespace vkcv // input assembly state vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo( - {}, - vk::PrimitiveTopology::eTriangleList, - false + {}, + primitiveTopologyToVulkanPrimitiveTopology(config.m_PrimitiveTopology), + false ); // viewport state @@ -148,6 +157,14 @@ namespace vkcv 0.f, 1.f ); + vk::PipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterization; + if (config.m_UseConservativeRasterization) { + conservativeRasterization = vk::PipelineRasterizationConservativeStateCreateInfoEXT( + {}, + vk::ConservativeRasterizationModeEXT::eOverestimate, + 0.f); + pipelineRasterizationStateCreateInfo.pNext = &conservativeRasterization; + } // multisample state vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo( @@ -238,6 +255,20 @@ namespace vkcv // graphics pipeline create std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo }; + + const char *geometryShaderName = "main"; // outside of if to make sure it stays in scope + vk::ShaderModule geometryModule; + if (config.m_ShaderProgram.existsShader(ShaderStage::GEOMETRY)) { + const vkcv::Shader geometryShader = config.m_ShaderProgram.getShader(ShaderStage::GEOMETRY); + const auto& geometryCode = geometryShader.shaderCode; + const vk::ShaderModuleCreateInfo geometryModuleInfo({}, geometryCode.size(), reinterpret_cast<const uint32_t*>(geometryCode.data())); + if (m_Device.createShaderModule(&geometryModuleInfo, nullptr, &geometryModule) != vk::Result::eSuccess) { + return PipelineHandle(); + } + vk::PipelineShaderStageCreateInfo geometryStage({}, vk::ShaderStageFlagBits::eGeometry, geometryModule, geometryShaderName); + shaderStages.push_back(geometryStage); + } + const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( {}, static_cast<uint32_t>(shaderStages.size()), @@ -263,11 +294,18 @@ namespace vkcv { m_Device.destroy(vertexModule); m_Device.destroy(fragmentModule); + if (geometryModule) { + m_Device.destroy(geometryModule); + } + m_Device.destroy(); return PipelineHandle(); } m_Device.destroy(vertexModule); m_Device.destroy(fragmentModule); + if (geometryModule) { + m_Device.destroy(geometryModule); + } const uint64_t id = m_Pipelines.size(); m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config }); diff --git a/src/vkcv/Swapchain.cpp b/src/vkcv/Swapchain.cpp index 639e949bc442588ece4e13b92bd032ecbd513352..33714adac7cec7c1b5e0013387424c4f865454ab 100644 --- a/src/vkcv/Swapchain.cpp +++ b/src/vkcv/Swapchain.cpp @@ -186,7 +186,7 @@ namespace vkcv chosenSurfaceFormat.colorSpace, // imageColorSpace chosenExtent, // imageExtent 1, // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers" - vk::ImageUsageFlagBits::eColorAttachment, // imageUsage TODO: what attachments? only color? depth? + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, // imageUsage TODO: what attachments? only color? depth? vk::SharingMode::eExclusive, // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues" 0, // queueFamilyIndexCount, the number of queue families having access to the image(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT nullptr, // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT @@ -227,7 +227,7 @@ namespace vkcv m_ColorSpace, extent2D, 1, - vk::ImageUsageFlagBits::eColorAttachment, + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, vk::SharingMode::eExclusive, 0, nullptr,