diff --git a/.gitmodules b/.gitmodules index efa79ed703e1cc83f962cebfd4299621810cf82e..c9eb19ee6ba09ded88a81b5ad253b2ae8c73c814 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,6 @@ [submodule "lib/VulkanMemoryAllocator-Hpp"] path = lib/VulkanMemoryAllocator-Hpp url = https://github.com/YaaZ/VulkanMemoryAllocator-Hpp.git +[submodule "modules/algorithm/lib/FidelityFX-SPD"] + path = modules/algorithm/lib/FidelityFX-SPD + url = https://github.com/GPUOpen-Effects/FidelityFX-SPD.git diff --git a/config/Sources.cmake b/config/Sources.cmake index ad7b1bbf84ea515af449b81c505de24d8cf0ecf9..2efd34c3e0158082ee539413431278aeb41e1a1c 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -71,9 +71,6 @@ set(vkcv_sources ${vkcv_include}/vkcv/QueueManager.hpp ${vkcv_source}/vkcv/QueueManager.cpp - ${vkcv_source}/vkcv/ImageLayoutTransitions.hpp - ${vkcv_source}/vkcv/ImageLayoutTransitions.cpp - ${vkcv_include}/vkcv/VertexLayout.hpp ${vkcv_source}/vkcv/VertexLayout.cpp @@ -109,4 +106,10 @@ set(vkcv_sources ${vkcv_include}/vkcv/ImageConfig.hpp ${vkcv_source}/vkcv/ImageConfig.cpp + + ${vkcv_include}/vkcv/Downsampler.hpp + ${vkcv_source}/vkcv/Downsampler.cpp + + ${vkcv_include}/vkcv/BlitDownsampler.hpp + ${vkcv_source}/vkcv/BlitDownsampler.cpp ) diff --git a/include/vkcv/BlitDownsampler.hpp b/include/vkcv/BlitDownsampler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a7e7e47793e35fbf6f6de084faabfe776266bac3 --- /dev/null +++ b/include/vkcv/BlitDownsampler.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "Downsampler.hpp" + +namespace vkcv { + + class ImageManager; + + class BlitDownsampler : public Downsampler { + friend class Core; + private: + ImageManager& m_imageManager; + + BlitDownsampler(Core& core, + ImageManager& imageManager); + + public: + void recordDownsampling(const CommandStreamHandle& cmdStream, + const ImageHandle& image) const override; + }; + +} diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 6505599489f405d135d33ce1c4aeeba295e2176a..dacf9697ca2cc55389c6288769393dfdd5bff128 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -16,6 +16,7 @@ #include "Handles.hpp" #include "Buffer.hpp" #include "Image.hpp" +#include "BlitDownsampler.hpp" #include "GraphicsPipelineConfig.hpp" #include "ComputePipelineConfig.hpp" #include "CommandResources.hpp" @@ -92,6 +93,8 @@ namespace vkcv CommandResources m_CommandResources; SyncResources m_SyncResources; uint32_t m_currentSwapchainImageIndex; + + std::unique_ptr<Downsampler> m_downsampler; /** * Sets up swapchain images @@ -241,6 +244,14 @@ namespace vkcv bool supportStorage = false, bool supportColorAttachment = false, Multisampling multisampling = Multisampling::None); + + /** + * @brief Returns the default blit-downsampler. + * + * @return Blit-downsampler + */ + [[nodiscard]] + const Downsampler& getDownsampler() const; /** * Creates a new window and returns it's handle @@ -558,9 +569,11 @@ namespace vkcv /** * @brief Submit command stream to GPU for actual execution * - * @param handle command stream to submit + * @param[in] handle Command stream to submit + * @param[in] signalRendering Flag to specify if the command stream finishes rendering */ - void submitCommandStream(const CommandStreamHandle& handle); + void submitCommandStream(const CommandStreamHandle& handle, + bool signalRendering = true); /** * @brief Prepare swapchain image for presentation to screen. @@ -574,19 +587,29 @@ namespace vkcv * @brief Prepare image for use as a sampled image. * Handles internal state such as image format, also acts as a memory barrier * - * @param cmdStream Handle of the command stream to record the preparation commands to - * @param image Handle of the image to prepare + * @param[in] cmdStream Handle of the command stream to record the preparation commands to + * @param[in] image Handle of the image to prepare + * @param[in] mipLevelCount Count of mip levels to prepare + * @param[in] mipLevelOffset Offset to start preparing mip levels */ - void prepareImageForSampling(const CommandStreamHandle& cmdStream, const ImageHandle& image); + void prepareImageForSampling(const CommandStreamHandle& cmdStream, + const ImageHandle& image, + uint32_t mipLevelCount = 0, + uint32_t mipLevelOffset = 0); /** * @brief Prepare image for use as a storage image. * Handles internal state such as image format, also acts as a memory barrier * - * @param cmdStream Handle of the command stream to record the preparation commands to - * @param image Handle of the image to prepare - */ - void prepareImageForStorage(const CommandStreamHandle& cmdStream, const ImageHandle& image); + * @param[in] cmdStream Handle of the command stream to record the preparation commands to + * @param[in] image Handle of the image to prepare + * @param[in] mipLevelCount Count of mip levels to prepare + * @param[in] mipLevelOffset Offset to start preparing mip levels + */ + void prepareImageForStorage(const CommandStreamHandle& cmdStream, + const ImageHandle& image, + uint32_t mipLevelCount = 0, + uint32_t mipLevelOffset = 0); /** * @brief Manual trigger to record commands to prepare an image for use as an attachment diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp index b8468bfdfd4cd20e59742f410ff8716be4e910fa..9d3269feb96c1828eb0c626bef332b7b9d68ed45 100644 --- a/include/vkcv/DescriptorWrites.hpp +++ b/include/vkcv/DescriptorWrites.hpp @@ -20,6 +20,7 @@ namespace vkcv { uint32_t mipLevel; bool useGeneralLayout; uint32_t arrayIndex; + uint32_t mipCount; }; /** @@ -29,6 +30,7 @@ namespace vkcv { uint32_t binding; ImageHandle image; uint32_t mipLevel; + uint32_t mipCount; }; /** @@ -81,13 +83,15 @@ namespace vkcv { * @param[in] mipLevel Mip level index * @param[in] useGeneralLayout Flag to use a general layout * @param[in] arrayIndex Image array index + * @param[in] mipCount Mip level count * @return Instance of descriptor writes */ DescriptorWrites& writeSampledImage(uint32_t binding, ImageHandle image, uint32_t mipLevel = 0, bool useGeneralLayout = false, - uint32_t arrayIndex = 0); + uint32_t arrayIndex = 0, + uint32_t mipCount = 1); /** * @brief Adds an entry to write an image to a given binding @@ -96,11 +100,13 @@ namespace vkcv { * @param[in] binding Binding index * @param[in,out] image Image handle * @param[in] mipLevel Mip level index + * @param[in] mipCount Mip level count * @return Instance of descriptor writes */ DescriptorWrites& writeStorageImage(uint32_t binding, ImageHandle image, - uint32_t mipLevel = 0); + uint32_t mipLevel = 0, + uint32_t mipCount = 1); /** * @brief Adds an entry to write a buffer to a given binding diff --git a/include/vkcv/Downsampler.hpp b/include/vkcv/Downsampler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ae491ea3e7cb7e1ef50f15f699b6e53e66276321 --- /dev/null +++ b/include/vkcv/Downsampler.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include "Handles.hpp" + +namespace vkcv { + + class Core; + + /** + * An abstract class to handle downsampling of images for mip generation. + */ + class Downsampler { + protected: + /** + * Reference to the current Core instance. + */ + Core& m_core; + + public: + /** + * Constructor to create a downsampler instance. + * @param[in,out] core Reference to a Core instance + */ + explicit Downsampler(Core& core); + + ~Downsampler() = default; + + /** + * Record the commands of the given downsampler instance to + * scale the image down on its own mip levels. + * + * @param[in] cmdStream + * @param[in] image + */ + virtual void recordDownsampling(const CommandStreamHandle& cmdStream, + const ImageHandle& image) const = 0; + + }; + +} \ No newline at end of file diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp index 51e422c949b66fe021ec3a5afd95f50a94e39544..e15ad7670795d4ffaf879248612bbbc5cf8cfb74 100644 --- a/include/vkcv/FeatureManager.hpp +++ b/include/vkcv/FeatureManager.hpp @@ -440,13 +440,37 @@ namespace vkcv { } /** - * @brief Return feature structure chain to request activated features. + * @brief Return feature structure chain to request all activated features. * * @return Head of feature structure chain */ [[nodiscard]] const vk::PhysicalDeviceFeatures2& getFeatures() const; + /** + * @brief Checks all activated features for a specific feature and returns its state. + * + * @tparam T Template parameter to use specific base structure types + * @param[in] type Vulkan structure type identifier + * @param[in] featureTestFunction Function to test feature structure with for requested attributes + * @return True, if the requested attributes are available, else false + */ + template<typename T> + bool checkFeatures(vk::StructureType type, + const std::function<bool(const T&)>& featureTestFunction) const { + const auto* base = reinterpret_cast<const vk::BaseInStructure*>(&getFeatures()); + + while (base) { + if ((base->sType == type) && (featureTestFunction(*reinterpret_cast<const T*>(base)))) { + return true; + } + + base = base->pNext; + } + + return false; + } + }; } diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 5d5359288d4b1b1f38bfabf062c9cc4cd0ca9ad1..3cb115fd9b84bed4b03717581193fb174dd27889 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -12,6 +12,7 @@ namespace vkcv { + class Downsampler; class ImageManager; /** @@ -95,19 +96,15 @@ namespace vkcv { */ void fill(const void* data, size_t size = SIZE_MAX); - /** - * @brief Generates the entire mip chain from mip level zero, - * returns after operation is finished - */ - void generateMipChainImmediate(); - /** * @brief Records mip chain generation to command stream, * mip level zero is used as source * * @param[out] cmdStream Command stream that the commands are recorded into + * @param[in] downsampler Downsampler to generate mip levels with */ - void recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream); + void recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream, + const Downsampler &downsampler); private: // TODO: const qualifier removed, very hacky!!! diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 0a7f0f0ab1b71f78c6a548caf3d82442a05dcb2b..1bd5a48df5ea3c53a26509e76aa8daed0fea5b10 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -3,6 +3,7 @@ set(vkcv_modules_includes) set(vkcv_modules_libraries) # Add new modules here: +add_subdirectory(algorithm) add_subdirectory(asset_loader) add_subdirectory(camera) add_subdirectory(effects) diff --git a/modules/algorithm/CMakeLists.txt b/modules/algorithm/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4eeaa261d10f50bd6c4bc8a43455cb252be50cf --- /dev/null +++ b/modules/algorithm/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 3.16) +project(vkcv_algorithm) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(vkcv_algorithm_source ${PROJECT_SOURCE_DIR}/src) +set(vkcv_algorithm_include ${PROJECT_SOURCE_DIR}/include) + +set(vkcv_algorithm_sources + ${vkcv_algorithm_include}/vkcv/algorithm/SinglePassDownsampler.hpp + ${vkcv_algorithm_source}/vkcv/algorithm/SinglePassDownsampler.cpp +) + +# Setup some path variables to load libraries +set(vkcv_algorithm_lib lib) +set(vkcv_algorithm_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_algorithm_lib}) + +# Check and load FidelityFX_SPD +include(config/FidelityFX_SPD.cmake) + +# adding source files to the project +add_library(vkcv_algorithm ${vkcv_build_attribute} ${vkcv_algorithm_sources}) + +# link the required libraries to the module +target_link_libraries(vkcv_algorithm ${vkcv_algorithm_libraries} vkcv vkcv_shader_compiler vkcv_camera vkcv_asset_loader) + +# including headers of dependencies and the VkCV framework +target_include_directories(vkcv_algorithm SYSTEM BEFORE PRIVATE ${vkcv_algorithm_includes} ${vkcv_include} ${vkcv_includes} ${vkcv_shader_compiler_include}) + +# add the own include directory for public headers +target_include_directories(vkcv_algorithm BEFORE PUBLIC ${vkcv_algorithm_include}) + +if (vkcv_parent_scope) + list(APPEND vkcv_modules_includes ${vkcv_algorithm_include}) + list(APPEND vkcv_modules_libraries vkcv_algorithm) + + set(vkcv_modules_includes ${vkcv_modules_includes} PARENT_SCOPE) + set(vkcv_modules_libraries ${vkcv_modules_libraries} PARENT_SCOPE) +endif() diff --git a/modules/algorithm/config/FidelityFX_SPD.cmake b/modules/algorithm/config/FidelityFX_SPD.cmake new file mode 100644 index 0000000000000000000000000000000000000000..eec11bfde46e7079417cabfbdc47a9e387877bff --- /dev/null +++ b/modules/algorithm/config/FidelityFX_SPD.cmake @@ -0,0 +1,21 @@ + +use_git_submodule("${vkcv_algorithm_lib_path}/FidelityFX-SPD" ffx_spd_status) + +if (${ffx_spd_status}) + include_shader(${vkcv_algorithm_lib_path}/FidelityFX-SPD/ffx-spd/ffx_a.h ${vkcv_algorithm_include} ${vkcv_algorithm_source}) + include_shader(${vkcv_algorithm_lib_path}/FidelityFX-SPD/ffx-spd/ffx_spd.h ${vkcv_algorithm_include} ${vkcv_algorithm_source}) + include_shader(${vkcv_algorithm_lib_path}/FidelityFX-SPD/sample/src/VK/SPDIntegration.glsl ${vkcv_algorithm_include} ${vkcv_algorithm_source}) + include_shader(${vkcv_algorithm_lib_path}/FidelityFX-SPD/sample/src/VK/SPDIntegrationLinearSampler.glsl ${vkcv_algorithm_include} ${vkcv_algorithm_source}) + + list(APPEND vkcv_algorithm_includes ${vkcv_algorithm_lib}/FidelityFX-SPD/ffx-spd) + + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_source}/ffx_a.h.cxx) + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_source}/ffx_spd.h.cxx) + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_source}/SPDIntegration.glsl.cxx) + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_source}/SPDIntegrationLinearSampler.glsl.cxx) + + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_include}/ffx_a.h.hxx) + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_include}/ffx_spd.h.hxx) + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_include}/SPDIntegration.glsl.hxx) + list(APPEND vkcv_algorithm_sources ${vkcv_algorithm_include}/SPDIntegrationLinearSampler.glsl.hxx) +endif () diff --git a/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp b/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c2869affda1ca0af33ad511f661ac41ca2e036d8 --- /dev/null +++ b/modules/algorithm/include/vkcv/algorithm/SinglePassDownsampler.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include <vkcv/Core.hpp> +#include <vkcv/Downsampler.hpp> +#include <vkcv/ShaderProgram.hpp> + +namespace vkcv::algorithm { + +#define SPD_MAX_MIP_LEVELS 12 + + struct SPDConstants { + int mips; + int numWorkGroupsPerSlice; + int workGroupOffset[2]; + }; + + struct SPDConstantsSampler { + int mips; + int numWorkGroupsPerSlice; + int workGroupOffset[2]; + float invInputSize[2]; + float padding[2]; + }; + + class SinglePassDownsampler : public vkcv::Downsampler { + private: + ComputePipelineHandle m_pipeline; + + DescriptorSetLayoutHandle m_descriptorSetLayout; + DescriptorSetHandle m_descriptorSet; + + Buffer<uint32_t> m_globalCounter; + + SamplerHandle m_sampler; + + public: + explicit SinglePassDownsampler(Core& core, + const SamplerHandle &sampler = SamplerHandle()); + + void recordDownsampling(const CommandStreamHandle& cmdStream, + const ImageHandle& image) const override; + + }; + +} diff --git a/modules/algorithm/lib/FidelityFX-SPD b/modules/algorithm/lib/FidelityFX-SPD new file mode 160000 index 0000000000000000000000000000000000000000..7c796c6d9fa6a9439e3610478148cfd742d97daf --- /dev/null +++ b/modules/algorithm/lib/FidelityFX-SPD @@ -0,0 +1 @@ +Subproject commit 7c796c6d9fa6a9439e3610478148cfd742d97daf diff --git a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d715fbdabc7cbcfb8a52a11997df23abe98499ef --- /dev/null +++ b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp @@ -0,0 +1,287 @@ + +#include "vkcv/algorithm/SinglePassDownsampler.hpp" + +#include <cstdint> +#include <cmath> + +#define A_CPU 1 +#include <ffx_a.h> +#include <ffx_spd.h> + +#include "ffx_a.h.hxx" +#include "ffx_spd.h.hxx" +#include "SPDIntegration.glsl.hxx" +#include "SPDIntegrationLinearSampler.glsl.hxx" + +#include <vkcv/File.hpp> +#include <vkcv/Logger.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> + +namespace vkcv::algorithm { + + static DescriptorBindings getDescriptorBindings(const SamplerHandle &sampler) { + DescriptorBindings descriptorBindings = {}; + + auto binding_0 = DescriptorBinding { + 0, + DescriptorType::IMAGE_STORAGE, + SPD_MAX_MIP_LEVELS + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_1 = DescriptorBinding { + 1, + DescriptorType::IMAGE_STORAGE, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_2 = DescriptorBinding{ + 2, + DescriptorType::STORAGE_BUFFER, + 1, + ShaderStage::COMPUTE, + false + }; + + auto binding_3 = DescriptorBinding{ + 3, + DescriptorType::IMAGE_SAMPLED, + 1, + ShaderStage::COMPUTE + }; + + auto binding_4 = DescriptorBinding{ + 4, + DescriptorType::SAMPLER, + 1, + ShaderStage::COMPUTE + }; + + descriptorBindings.insert(std::make_pair(0, binding_0)); + descriptorBindings.insert(std::make_pair(1, binding_1)); + descriptorBindings.insert(std::make_pair(2, binding_2)); + + if (sampler) { + descriptorBindings.insert(std::make_pair(3, binding_3)); + descriptorBindings.insert(std::make_pair(4, binding_4)); + } + + return descriptorBindings; + } + + static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { + std::ofstream file (shaderPath.string(), std::ios::out); + + if (!file.is_open()) { + vkcv_log(LogLevel::ERROR, "The file could not be opened (%s)", shaderPath.string().c_str()); + return false; + } + + file.seekp(0); + file.write(code.c_str(), static_cast<std::streamsize>(code.length())); + file.close(); + + return true; + } + + static bool compileSPDShader(vkcv::shader::GLSLCompiler& compiler, + const std::string &source, + const shader::ShaderCompiledFunction& compiled) { + std::filesystem::path directory = generateTemporaryDirectoryPath(); + + if (!std::filesystem::create_directory(directory)) { + vkcv_log(LogLevel::ERROR, "The directory could not be created (%s)", directory.string().c_str()); + return false; + } + + if (!writeShaderCode(directory / "ffx_a.h", FFX_A_H_SHADER)) { + return false; + } + + if (!writeShaderCode(directory / "ffx_spd.h", FFX_SPD_H_SHADER)) { + return false; + } + + return compiler.compileSource( + vkcv::ShaderStage::COMPUTE, + source.c_str(), + [&directory, &compiled] (vkcv::ShaderStage shaderStage, + const std::filesystem::path& path) { + if (compiled) { + compiled(shaderStage, path); + } + + std::filesystem::remove_all(directory); + }, directory + ); + } + + SinglePassDownsampler::SinglePassDownsampler(Core &core, + const SamplerHandle &sampler) : + vkcv::Downsampler(core), + m_pipeline(), + + m_descriptorSetLayout(m_core.createDescriptorSetLayout(getDescriptorBindings(sampler))), + m_descriptorSet(m_core.createDescriptorSet(m_descriptorSetLayout)), + + m_globalCounter(m_core.createBuffer<uint32_t>( + vkcv::BufferType::STORAGE, + 6 + )), + + m_sampler(sampler) { + vkcv::shader::GLSLCompiler compiler (vkcv::shader::GLSLCompileTarget::SUBGROUP_OP); + + vk::PhysicalDeviceSubgroupProperties subgroupProperties; + + vk::PhysicalDeviceProperties2 properties2; + properties2.pNext = &subgroupProperties; + m_core.getContext().getPhysicalDevice().getProperties2(&properties2); + + const bool no_subgroup_quad = !(subgroupProperties.supportedOperations & vk::SubgroupFeatureFlagBits::eQuad); + + if (no_subgroup_quad) { + compiler.setDefine("SPD_NO_WAVE_OPERATIONS", "1"); + } + + const auto& featureManager = m_core.getContext().getFeatureManager(); + + const bool float16Support = ( + featureManager.checkFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>( + vk::StructureType::ePhysicalDeviceShaderFloat16Int8FeaturesKHR, + [](const vk::PhysicalDeviceFloat16Int8FeaturesKHR& features) { + return features.shaderFloat16; + } + ) && + featureManager.checkFeatures<vk::PhysicalDevice16BitStorageFeaturesKHR>( + vk::StructureType::ePhysicalDevice16BitStorageFeaturesKHR, + [](const vk::PhysicalDevice16BitStorageFeaturesKHR& features) { + return features.storageBuffer16BitAccess; + } + ) && + ((no_subgroup_quad) || + (featureManager.checkFeatures<vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures>( + vk::StructureType::ePhysicalDeviceShaderSubgroupExtendedTypesFeatures, + [](const vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures& features) { + return features.shaderSubgroupExtendedTypes; + } + ))) + ); + + if (float16Support) { + compiler.setDefine("A_HALF", "1"); + compiler.setDefine("SPD_PACKED_ONLY", "1"); + } + + ShaderProgram program; + if (m_sampler) { + compileSPDShader( + compiler, + SPDINTEGRATIONLINEARSAMPLER_GLSL_SHADER, + [&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + program.addShader(shaderStage, path); + } + ); + } else { + compileSPDShader( + compiler, + SPDINTEGRATION_GLSL_SHADER, + [&program](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { + program.addShader(shaderStage, path); + } + ); + } + + m_pipeline = m_core.createComputePipeline({program,{ + m_descriptorSetLayout + }}); + + uint32_t zeroes [m_globalCounter.getCount()]; + memset(zeroes, 0, m_globalCounter.getSize()); + m_globalCounter.fill(zeroes); + + vkcv::DescriptorWrites writes; + writes.writeStorageBuffer(2, m_globalCounter.getHandle()); + + if (m_sampler) { + writes.writeSampler(4, m_sampler); + } + + m_core.writeDescriptorSet(m_descriptorSet, writes); + } + + void SinglePassDownsampler::recordDownsampling(const CommandStreamHandle &cmdStream, + const ImageHandle &image) const { + vkcv::DescriptorWrites writes; + writes.writeStorageImage(1, image, 6); + + if (m_sampler) { + writes.writeStorageImage(0, image, 0, m_core.getImageMipLevels(image) - 1); + writes.writeSampledImage(3, image); + } else { + writes.writeStorageImage(0, image, 0, m_core.getImageMipLevels(image)); + } + + m_core.writeDescriptorSet(m_descriptorSet, writes); + + varAU2(dispatchThreadGroupCountXY); + varAU2(workGroupOffset); + varAU2(numWorkGroupsAndMips); + varAU4(rectInfo) = initAU4( + 0, + 0, + m_core.getImageWidth(image), + m_core.getImageHeight(image) + ); + + SpdSetup(dispatchThreadGroupCountXY, workGroupOffset, numWorkGroupsAndMips, rectInfo); + + if (m_sampler) { + m_core.prepareImageForStorage(cmdStream, image, m_core.getImageMipLevels(image) - 1, 1); + m_core.prepareImageForSampling(cmdStream, image, 1); + } else { + m_core.prepareImageForStorage(cmdStream, image); + } + + uint32_t dispatch [3]; + dispatch[0] = dispatchThreadGroupCountXY[0]; + dispatch[1] = dispatchThreadGroupCountXY[1]; + dispatch[2] = 1; // TODO: No array size supported by images yet! + + vkcv::PushConstants pushConstants (m_sampler? sizeof(SPDConstantsSampler) : sizeof(SPDConstants)); + + if (m_sampler) { + SPDConstantsSampler data; + data.numWorkGroupsPerSlice = numWorkGroupsAndMips[0]; + data.mips = numWorkGroupsAndMips[1]; + data.workGroupOffset[0] = workGroupOffset[0]; + data.workGroupOffset[1] = workGroupOffset[1]; + data.invInputSize[0] = 1.0f / m_core.getImageWidth(image); + data.invInputSize[1] = 1.0f / m_core.getImageHeight(image); + + pushConstants.appendDrawcall<SPDConstantsSampler>(data); + } else { + SPDConstants data; + data.numWorkGroupsPerSlice = numWorkGroupsAndMips[0]; + data.mips = numWorkGroupsAndMips[1]; + data.workGroupOffset[0] = workGroupOffset[0]; + data.workGroupOffset[1] = workGroupOffset[1]; + + pushConstants.appendDrawcall<SPDConstants>(data); + } + + m_core.recordComputeDispatchToCmdStream(cmdStream, m_pipeline, dispatch, { + vkcv::DescriptorSetUsage(0, m_descriptorSet) + }, pushConstants); + + if (m_sampler) { + m_core.prepareImageForSampling(cmdStream, image, m_core.getImageMipLevels(image) - 1, 1); + } else { + m_core.prepareImageForSampling(cmdStream, image); + } + } + +} diff --git a/modules/material/include/vkcv/material/Material.hpp b/modules/material/include/vkcv/material/Material.hpp index 7251bda151cab9f812114f8a7a707597c476ad21..c47d0c5ba084e845b8a364ce0ebf5e71539bfd9a 100644 --- a/modules/material/include/vkcv/material/Material.hpp +++ b/modules/material/include/vkcv/material/Material.hpp @@ -3,6 +3,7 @@ #include <vector> #include <vkcv/Core.hpp> +#include <vkcv/Downsampler.hpp> #include <vkcv/Handles.hpp> namespace vkcv::material { @@ -146,6 +147,15 @@ namespace vkcv::material { * @return true if the material is invalid, otherwise false */ bool operator!() const; + + /** + * @brief Records mip chain generation to command stream of the whole material. + * + * @param[out] cmdStream Command stream that the commands are recorded into + * @param[in] downsampler Downsampler to generate mip levels with + */ + void recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream, + const Downsampler &downsampler); /** * Returns the descriptor bindings required by a given material diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp index 2bd18e8342a24d6311182c9c0c2d640d3cbfa185..a1054ed021fb087397e2fae5899777507fe21fa8 100644 --- a/modules/material/src/vkcv/material/Material.cpp +++ b/modules/material/src/vkcv/material/Material.cpp @@ -27,6 +27,13 @@ namespace vkcv::material { return (m_Type == MaterialType::UNKNOWN); } + void Material::recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream, + const Downsampler &downsampler) { + for (auto& texture : m_Textures) { + downsampler.recordDownsampling(cmdStream, texture.m_Image); + } + } + const DescriptorBindings& Material::getDescriptorBindings(MaterialType type) { static DescriptorBindings pbr_bindings = {}; diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index cd02004f56ea3dfddcd20618b7859a0699d92d71..695e568444d4fe916c67b79965034a1c30d50623 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -274,6 +274,14 @@ namespace vkcv::scene { scene.getNode(root).loadMesh(asset_scene, mesh); } + auto mipStream = core.createCommandStream(vkcv::QueueType::Graphics); + + for (auto& material : scene.m_materials) { + material.m_data.recordMipChainGeneration(mipStream, core.getDownsampler()); + } + + core.submitCommandStream(mipStream, false); + scene.getNode(root).splitMeshesToSubNodes(128); return scene; } diff --git a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp index e457874ad2abc4cc3bfe9ab74fdb8d35446b5db1..face4cba350122f22feee6bae878397dccf4a070 100644 --- a/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp +++ b/modules/shader_compiler/include/vkcv/shader/GLSLCompiler.hpp @@ -11,17 +11,28 @@ namespace vkcv::shader { * @addtogroup vkcv_shader * @{ */ + + enum class GLSLCompileTarget { + SUBGROUP_OP, + RAY_TRACING, + + UNKNOWN + }; /** * A class to handle GLSL runtime shader compilation. */ class GLSLCompiler : public Compiler { private: + GLSLCompileTarget m_target; + public: /** * The constructor of a runtime GLSL shader compiler instance. + * + * @param[in] target Compile target (optional) */ - GLSLCompiler(); + GLSLCompiler(GLSLCompileTarget target = GLSLCompileTarget::UNKNOWN); /** * The copy-constructor of a runtime GLSL shader compiler instance. diff --git a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp index c639118f5a4482eb9db2cee46057e5662b472181..78a82113f89bd54914471d64fee6e11700548431 100644 --- a/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp +++ b/modules/shader_compiler/src/vkcv/shader/GLSLCompiler.cpp @@ -13,7 +13,9 @@ namespace vkcv::shader { static uint32_t s_CompilerCount = 0; - GLSLCompiler::GLSLCompiler() : Compiler() { + GLSLCompiler::GLSLCompiler(GLSLCompileTarget target) : + Compiler(), + m_target(target) { if (s_CompilerCount == 0) { glslang::InitializeProcess(); } @@ -56,17 +58,17 @@ namespace vkcv::shader { return EShLangTaskNV; case ShaderStage::MESH: return EShLangMeshNV; - case ShaderStage::RAY_GEN: // for RTX + case ShaderStage::RAY_GEN: return EShLangRayGen; - case ShaderStage::RAY_CLOSEST_HIT: // for RTX + case ShaderStage::RAY_CLOSEST_HIT: return EShLangClosestHit; - case ShaderStage::RAY_MISS: // for RTX + case ShaderStage::RAY_MISS: return EShLangMiss; - case ShaderStage::RAY_INTERSECTION: // for RTX + case ShaderStage::RAY_INTERSECTION: return EShLangIntersect; - case ShaderStage::RAY_ANY_HIT: // for RTX + case ShaderStage::RAY_ANY_HIT: return EShLangAnyHit; - case ShaderStage::RAY_CALLABLE: // for RTX + case ShaderStage::RAY_CALLABLE: return EShLangCallable; default: return EShLangCount; @@ -226,18 +228,20 @@ namespace vkcv::shader { } glslang::TShader shader (language); - - // configure environment for rtx shaders by adjusting versions of Vulkan and SPIR-V, else rtx shader cannot be compiled. - if((shaderStage == ShaderStage::RAY_GEN) || (shaderStage == ShaderStage::RAY_ANY_HIT) - || (shaderStage == ShaderStage::RAY_CLOSEST_HIT) || (shaderStage == ShaderStage::RAY_MISS) - || (shaderStage == ShaderStage::RAY_INTERSECTION) || (shaderStage == ShaderStage::RAY_CALLABLE)){ - - shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_2); - shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_4); + switch (m_target) { + case GLSLCompileTarget::SUBGROUP_OP: + shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_1); + shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_3); + break; + case GLSLCompileTarget::RAY_TRACING: + shader.setEnvClient(glslang::EShClientVulkan,glslang::EShTargetVulkan_1_2); + shader.setEnvTarget(glslang::EShTargetSpv,glslang::EShTargetSpv_1_4); + break; + default: + break; } glslang::TProgram program; - std::string source (shaderSource); if (!m_defines.empty()) { diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index a2009440acffd1e9a82c4832b0d2cf4e1c92b34b..a470cd21aba04faf7087e883cadfecb322876553 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -107,26 +107,6 @@ namespace vkcv::upscaling { return descriptorBindings; } - template<typename T> - bool checkFeatures(const vk::BaseInStructure* base, vk::StructureType type, bool (*check)(const T& features)) { - if (base->sType == type) { - return check(*reinterpret_cast<const T*>(base)); - } else - if (base->pNext) { - return checkFeatures<T>(base->pNext, type, check); - } else { - return false; - } - } - - static bool checkFloat16(const vk::PhysicalDeviceFloat16Int8FeaturesKHR& features) { - return features.shaderFloat16; - } - - static bool check16Storage(const vk::PhysicalDevice16BitStorageFeaturesKHR& features) { - return features.storageBuffer16BitAccess; - } - static bool writeShaderCode(const std::filesystem::path &shaderPath, const std::string& code) { std::ofstream file (shaderPath.string(), std::ios::out); @@ -205,17 +185,20 @@ namespace vkcv::upscaling { vkcv::shader::GLSLCompiler easuCompiler; vkcv::shader::GLSLCompiler rcasCompiler; - const auto& features = m_core.getContext().getFeatureManager().getFeatures(); + const auto& featureManager = m_core.getContext().getFeatureManager(); + const bool float16Support = ( - checkFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>( - reinterpret_cast<const vk::BaseInStructure*>(&features), + featureManager.checkFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>( vk::StructureType::ePhysicalDeviceShaderFloat16Int8FeaturesKHR, - checkFloat16 + [](const vk::PhysicalDeviceFloat16Int8FeaturesKHR& features) { + return features.shaderFloat16; + } ) && - checkFeatures<vk::PhysicalDevice16BitStorageFeaturesKHR>( - reinterpret_cast<const vk::BaseInStructure*>(&features), + featureManager.checkFeatures<vk::PhysicalDevice16BitStorageFeaturesKHR>( vk::StructureType::ePhysicalDevice16BitStorageFeaturesKHR, - check16Storage + [](const vk::PhysicalDevice16BitStorageFeaturesKHR& features) { + return features.storageBuffer16BitAccess; + } ) ); diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp index 0986b0910b6e7486c2dc3fc244269672a58d0730..811e1162588fa699b4d74045504dc9c3d4de4f4c 100644 --- a/projects/bindless_textures/src/main.cpp +++ b/projects/bindless_textures/src/main.cpp @@ -56,15 +56,14 @@ int main(int argc, const char** argv) { "resources/cube/Grass001_1K_Displacement.jpg", "resources/cube/Grass001_1K_Normal.jpg", "resources/cube/Grass001_1K_Roughness.jpg" }; - for(uint32_t i = 0; i < 5; i++) + + for (uint32_t i = 0; i < 5; i++) { std::filesystem::path grassPath(grassPaths[i]); vkcv::asset::Texture grassTexture = vkcv::asset::loadTexture(grassPath); vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, grassTexture.width, grassTexture.height); texture.fill(grassTexture.data.data()); - texture.generateMipChainImmediate(); - texture.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); texturesArray.push_back(texture); } @@ -167,12 +166,20 @@ int main(int argc, const char** argv) { return EXIT_FAILURE; } - vkcv::asset::Texture &tex = mesh.textures[0]; - vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); - texture.fill(tex.data.data()); - texture.generateMipChainImmediate(); - texture.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); - texturesArray.push_back(texture); + { + vkcv::asset::Texture &tex = mesh.textures[0]; + vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); + texture.fill(tex.data.data()); + texturesArray.push_back(texture); + } + + auto downsampleStream = core.createCommandStream(vkcv::QueueType::Graphics); + + for (auto& texture : texturesArray) { + texture.recordMipChainGeneration(downsampleStream, core.getDownsampler()); + } + + core.submitCommandStream(downsampleStream, false); vkcv::SamplerHandle sampler = core.createSampler( vkcv::SamplerFilterType::LINEAR, diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index fe8acb3cfbb65de71763c2c30b50daf5f598234d..fa671a5507a7621586497048128e8959f72cdf08 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -127,8 +127,12 @@ int main(int argc, const char** argv) { vkcv::asset::Texture &tex = mesh.textures[0]; vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); texture.fill(tex.data.data()); - texture.generateMipChainImmediate(); - texture.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + + { + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + texture.recordMipChainGeneration(cmdStream, core.getDownsampler()); + core.submitCommandStream(cmdStream, false); + } vkcv::SamplerHandle sampler = core.createSampler( vkcv::SamplerFilterType::LINEAR, diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp index 342d2d705f831bc98705c9ecaaa5b369befda7b6..933f20db73313e25bc9e4863f2bf4530df26a366 100644 --- a/projects/indirect_dispatch/src/AppSetup.cpp +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -75,8 +75,12 @@ bool loadImage(vkcv::Core& core, const std::filesystem::path& path, vkcv::ImageH true); image.fill(textureData.data.data(), textureData.data.size()); - image.generateMipChainImmediate(); - image.switchLayout(vk::ImageLayout::eReadOnlyOptimalKHR); + + { + auto mipStream = core.createCommandStream(vkcv::QueueType::Graphics); + image.recordMipChainGeneration(mipStream, core.getDownsampler()); + core.submitCommandStream(mipStream, false); + } *outImage = image.getHandle(); return true; diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp index 16e3e83994a1a7ca14fa2163799ee8d034eb8deb..26f523958e9704d7fc090ceba818591d904a2e92 100644 --- a/projects/indirect_draw/src/main.cpp +++ b/projects/indirect_draw/src/main.cpp @@ -172,7 +172,9 @@ void compileMeshForIndirectDraw(vkcv::Core &core, vkcv::Image pseudoImg = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); std::vector<uint8_t> pseudoData = {0, 0, 0, 0}; pseudoImg.fill(pseudoData.data()); - pseudoImg.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + + auto mipStream = core.createCommandStream(vkcv::QueueType::Graphics); + pseudoImg.recordMipChainGeneration(mipStream, core.getDownsampler()); uint32_t vertexOffset = 0; for (const auto &mesh : scene.meshes) @@ -194,8 +196,7 @@ void compileMeshForIndirectDraw(vkcv::Core &core, vkcv::Image baseColorImg = core.createImage(vk::Format::eR8G8B8A8Srgb, baseColor.w, baseColor.h); baseColorImg.fill(baseColor.data.data()); - baseColorImg.generateMipChainImmediate(); - baseColorImg.switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + baseColorImg.recordMipChainGeneration(mipStream, core.getDownsampler()); compiledMat.baseColor.push_back(baseColorImg); } @@ -254,6 +255,8 @@ void compileMeshForIndirectDraw(vkcv::Core &core, } } } + + core.submitCommandStream(mipStream, false); } int main(int argc, const char** argv) { diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index 0276f05db5bece4416578d89da1fd7a7b31336ca..e1bfd2231bc8047f12ba7d71e6a176f1fd85d92c 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -43,7 +43,7 @@ int main(int argc, const char** argv) { std::vector<float> vertices = teapot.getVertices(); std::vector<uint32_t> indices = teapot.getIndices(); - vkcv::shader::GLSLCompiler compiler; + vkcv::shader::GLSLCompiler compiler (vkcv::shader::GLSLCompileTarget::RAY_TRACING); vkcv::ShaderProgram rtxShaderProgram; compiler.compile(vkcv::ShaderStage::RAY_GEN, std::filesystem::path("resources/shaders/ambientOcclusion.rgen"), diff --git a/projects/voxelization/CMakeLists.txt b/projects/voxelization/CMakeLists.txt index 0f0585d9d5d9a26cb2daec486f3df8c417a01527..22a4848aa5f5d0b4cdaf61cb48a6dafde4bb66d9 100644 --- a/projects/voxelization/CMakeLists.txt +++ b/projects/voxelization/CMakeLists.txt @@ -28,7 +28,8 @@ target_include_directories(voxelization SYSTEM BEFORE PRIVATE ${vkcv_shader_compiler_include} ${vkcv_gui_include} ${vkcv_upscaling_include} - ${vkcv_effects_include}) + ${vkcv_effects_include} + ${vkcv_algorithm_include}) # linking with libraries from all dependencies and the VkCV framework target_link_libraries(voxelization @@ -40,4 +41,5 @@ target_link_libraries(voxelization vkcv_shader_compiler vkcv_gui vkcv_upscaling - vkcv_effects) + vkcv_effects + vkcv_algorithm) diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp index 53a11ceb1306c8a567834e943d70a8862a34afa8..2d09f8a3137816e441c0fd4cf0e46da030356c5b 100644 --- a/projects/voxelization/src/ShadowMapping.cpp +++ b/projects/voxelization/src/ShadowMapping.cpp @@ -321,8 +321,7 @@ void ShadowMapping::recordShadowMapRendering( dispatchCount, { vkcv::DescriptorSetUsage(0, m_shadowBlurYDescriptorSet) }, vkcv::PushConstants(0)); - m_shadowMap.recordMipChainGeneration(cmdStream); - m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle()); + m_shadowMap.recordMipChainGeneration(cmdStream, m_corePtr->getDownsampler()); m_corePtr->recordEndDebugLabel(cmdStream); } diff --git a/projects/voxelization/src/Voxelization.cpp b/projects/voxelization/src/Voxelization.cpp index 616eed83e0687e03c1d9bfe0ee3127a72457d241..523a7a672ba09a259c77e2ee568a06c92533832e 100644 --- a/projects/voxelization/src/Voxelization.cpp +++ b/projects/voxelization/src/Voxelization.cpp @@ -314,8 +314,7 @@ void Voxelization::voxelizeMeshes( // intermediate image mipchain m_corePtr->recordBeginDebugLabel(cmdStream, "Intermediate Voxel mipmap generation", { 1, 1, 1, 1 }); - m_voxelImageIntermediate.recordMipChainGeneration(cmdStream); - m_corePtr->prepareImageForSampling(cmdStream, m_voxelImageIntermediate.getHandle()); + m_voxelImageIntermediate.recordMipChainGeneration(cmdStream, m_corePtr->getDownsampler()); m_corePtr->recordEndDebugLabel(cmdStream); // secondary bounce @@ -327,14 +326,12 @@ void Voxelization::voxelizeMeshes( bufferToImageDispatchCount, { vkcv::DescriptorSetUsage(0, m_secondaryBounceDescriptorSet) }, vkcv::PushConstants(0)); - m_voxelImage.recordMipChainGeneration(cmdStream); - m_corePtr->recordImageMemoryBarrier(cmdStream, m_voxelImage.getHandle()); + m_voxelImage.recordMipChainGeneration(cmdStream, m_corePtr->getDownsampler()); m_corePtr->recordEndDebugLabel(cmdStream); // final image mipchain m_corePtr->recordBeginDebugLabel(cmdStream, "Voxel mipmap generation", { 1, 1, 1, 1 }); - m_voxelImage.recordMipChainGeneration(cmdStream); - m_corePtr->prepareImageForSampling(cmdStream, m_voxelImage.getHandle()); + m_voxelImage.recordMipChainGeneration(cmdStream, m_corePtr->getDownsampler()); m_corePtr->recordEndDebugLabel(cmdStream); } diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index 02533e447724ad8d83c7af415b01acc2350126eb..02dc237e0fa84ac5a10c3a601556cda784b8d9c8 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -12,6 +12,7 @@ #include <vkcv/upscaling/BilinearUpscaling.hpp> #include <vkcv/upscaling/NISUpscaling.hpp> #include <vkcv/effects/BloomAndFlaresEffect.hpp> +#include <vkcv/algorithm/SinglePassDownsampler.hpp> int main(int argc, const char** argv) { const char* applicationName = "Voxelization"; @@ -21,6 +22,14 @@ int main(int argc, const char** argv) { vkcv::Features features; features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + features.tryExtensionFeature<vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures>( + VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME, + [](vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures& features) { + features.setShaderSubgroupExtendedTypes(true); + } + ); + features.tryExtensionFeature<vk::PhysicalDevice16BitStorageFeatures>( VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, [](vk::PhysicalDevice16BitStorageFeatures& features) { @@ -44,6 +53,7 @@ int main(int argc, const char** argv) { { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, features ); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); vkcv::Window& window = core.getWindow(windowHandle); @@ -240,6 +250,10 @@ int main(int argc, const char** argv) { std::vector<vkcv::DescriptorSetLayoutHandle> materialDescriptorSetLayouts; std::vector<vkcv::DescriptorSetHandle> materialDescriptorSets; std::vector<vkcv::Image> sceneImages; + + const vkcv::Downsampler &downsampler = core.getDownsampler(); + + auto mipStream = core.createCommandStream(vkcv::QueueType::Graphics); for (const auto& material : scene.materials) { int albedoIndex = material.baseColor; @@ -269,22 +283,19 @@ int main(int argc, const char** argv) { // albedo texture sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Srgb, albedoTexture.w, albedoTexture.h, 1, true)); sceneImages.back().fill(albedoTexture.data.data()); - sceneImages.back().generateMipChainImmediate(); - sceneImages.back().switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + sceneImages.back().recordMipChainGeneration(mipStream, downsampler); const vkcv::ImageHandle albedoHandle = sceneImages.back().getHandle(); // normal texture sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Unorm, normalTexture.w, normalTexture.h, 1, true)); sceneImages.back().fill(normalTexture.data.data()); - sceneImages.back().generateMipChainImmediate(); - sceneImages.back().switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + sceneImages.back().recordMipChainGeneration(mipStream, downsampler); const vkcv::ImageHandle normalHandle = sceneImages.back().getHandle(); // specular texture sceneImages.push_back(core.createImage(vk::Format::eR8G8B8A8Unorm, specularTexture.w, specularTexture.h, 1, true)); sceneImages.back().fill(specularTexture.data.data()); - sceneImages.back().generateMipChainImmediate(); - sceneImages.back().switchLayout(vk::ImageLayout::eShaderReadOnlyOptimal); + sceneImages.back().recordMipChainGeneration(mipStream, downsampler); const vkcv::ImageHandle specularHandle = sceneImages.back().getHandle(); vkcv::DescriptorWrites setWrites; @@ -299,6 +310,8 @@ int main(int argc, const char** argv) { setWrites.writeSampler(1, colorSampler); core.writeDescriptorSet(materialDescriptorSets.back(), setWrites); } + + core.submitCommandStream(mipStream, false); std::vector<vkcv::DescriptorSetLayoutHandle> perMeshDescriptorSetLayouts; std::vector<vkcv::DescriptorSetHandle> perMeshDescriptorSets; diff --git a/src/vkcv/BlitDownsampler.cpp b/src/vkcv/BlitDownsampler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce031549fd0ed831c6d771602b8205ce8401fc2c --- /dev/null +++ b/src/vkcv/BlitDownsampler.cpp @@ -0,0 +1,20 @@ + +#include "vkcv/BlitDownsampler.hpp" + +#include "vkcv/Core.hpp" +#include "ImageManager.hpp" + +namespace vkcv { + + BlitDownsampler::BlitDownsampler(Core &core, + ImageManager& imageManager) : + Downsampler(core), + m_imageManager(imageManager) {} + + void BlitDownsampler::recordDownsampling(const CommandStreamHandle &cmdStream, + const ImageHandle &image) const { + m_imageManager.recordImageMipChainGenerationToCmdStream(cmdStream, image); + m_core.prepareImageForSampling(cmdStream, image); + } + +} diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index df3170d1524b69d23a67c91d1ec94829bcc08c8c..383dcbb98e97e58bb20bfa0836aeec17201cf532 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -15,10 +15,10 @@ #include "ImageManager.hpp" #include "DescriptorManager.hpp" #include "WindowManager.hpp" -#include "ImageLayoutTransitions.hpp" #include "CommandStreamManager.hpp" #include <cmath> #include "vkcv/Logger.hpp" +#include "vkcv/BlitDownsampler.hpp" namespace vkcv { @@ -62,13 +62,15 @@ namespace vkcv m_WindowManager(std::make_unique<WindowManager>()), m_SwapchainManager(std::make_unique<SwapchainManager>()), m_CommandResources(commandResources), - m_SyncResources(syncResources) + m_SyncResources(syncResources), + m_downsampler(nullptr) { m_BufferManager->m_core = this; m_BufferManager->init(); m_CommandStreamManager->init(this); m_SwapchainManager->m_context = &m_Context; m_ImageManager->m_core = this; + m_downsampler = std::unique_ptr<Downsampler>(new BlitDownsampler(*this, *m_ImageManager)); } Core::~Core() noexcept { @@ -231,7 +233,7 @@ namespace vkcv const bool isDepthImage = isDepthFormat(imageManager.getImageFormat(handle)); const vk::ImageLayout targetLayout = isDepthImage ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal; - imageManager.recordImageLayoutTransition(handle, targetLayout, cmdBuffer); + imageManager.recordImageLayoutTransition(handle, 0, 0, targetLayout, cmdBuffer); } } @@ -809,10 +811,16 @@ namespace vkcv } } - void Core::submitCommandStream(const CommandStreamHandle& handle) { + void Core::submitCommandStream(const CommandStreamHandle& handle, + bool signalRendering) { std::vector<vk::Semaphore> waitSemaphores; + // FIXME: add proper user controllable sync - std::vector<vk::Semaphore> signalSemaphores = { m_SyncResources.renderFinished }; + std::vector<vk::Semaphore> signalSemaphores; + if (signalRendering) { + signalSemaphores.push_back(m_SyncResources.renderFinished); + } + m_CommandStreamManager->submitCommandStreamSynchronous(handle, waitSemaphores, signalSemaphores); } @@ -849,6 +857,10 @@ namespace vkcv supportColorAttachment, multisampling); } + + const Downsampler &Core::getDownsampler() const { + return *m_downsampler; + } WindowHandle Core::createWindow( const char *applicationName, @@ -928,19 +940,43 @@ namespace vkcv 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); + m_ImageManager->recordImageLayoutTransition( + swapchainHandle, + 0, + 0, + vk::ImageLayout::ePresentSrcKHR, + cmdBuffer + ); }, nullptr); } - void Core::prepareImageForSampling(const CommandStreamHandle& cmdStream, const ImageHandle& image) { - recordCommandsToStream(cmdStream, [image, this](const vk::CommandBuffer cmdBuffer) { - m_ImageManager->recordImageLayoutTransition(image, vk::ImageLayout::eShaderReadOnlyOptimal, cmdBuffer); + void Core::prepareImageForSampling(const CommandStreamHandle& cmdStream, + const ImageHandle& image, + uint32_t mipLevelCount, + uint32_t mipLevelOffset) { + recordCommandsToStream(cmdStream, [image, mipLevelCount, mipLevelOffset, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageLayoutTransition( + image, + mipLevelCount, + mipLevelOffset, + 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); + void Core::prepareImageForStorage(const CommandStreamHandle& cmdStream, + const ImageHandle& image, + uint32_t mipLevelCount, + uint32_t mipLevelOffset) { + recordCommandsToStream(cmdStream, [image, mipLevelCount, mipLevelOffset, this](const vk::CommandBuffer cmdBuffer) { + m_ImageManager->recordImageLayoutTransition( + image, + mipLevelCount, + mipLevelOffset, + vk::ImageLayout::eGeneral, + cmdBuffer + ); }, nullptr); } @@ -996,11 +1032,11 @@ namespace vkcv SamplerFilterType filterType) { recordCommandsToStream(cmdStream, [&](const vk::CommandBuffer cmdBuffer) { m_ImageManager->recordImageLayoutTransition( - src, vk::ImageLayout::eTransferSrcOptimal, cmdBuffer + src, 0, 0, vk::ImageLayout::eTransferSrcOptimal, cmdBuffer ); m_ImageManager->recordImageLayoutTransition( - dst, vk::ImageLayout::eTransferDstOptimal, cmdBuffer + dst, 0, 0, vk::ImageLayout::eTransferDstOptimal, cmdBuffer ); const std::array<vk::Offset3D, 2> srcOffsets = { diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp index d12a5287e2317bdfc21fb15872681138b4f0d64f..a7e2f06c98fb24608f667d529b226736bddace7d 100644 --- a/src/vkcv/DescriptorManager.cpp +++ b/src/vkcv/DescriptorManager.cpp @@ -163,6 +163,7 @@ namespace vkcv size_t bufferInfoIndex; uint32_t binding; uint32_t arrayElementIndex; + uint32_t descriptorCount; vk::DescriptorType type; }; @@ -181,20 +182,27 @@ namespace vkcv for (const auto& write : writes.getSampledImageWrites()) { - vk::ImageLayout layout = write.useGeneralLayout ? vk::ImageLayout::eGeneral : vk::ImageLayout::eShaderReadOnlyOptimal; - const vk::DescriptorImageInfo imageInfo( - nullptr, - imageManager.getVulkanImageView(write.image, write.mipLevel), - layout + const vk::ImageLayout layout = (write.useGeneralLayout? + vk::ImageLayout::eGeneral : + vk::ImageLayout::eShaderReadOnlyOptimal ); - imageInfos.push_back(imageInfo); + for (uint32_t i = 0; i < write.mipCount; i++) { + const vk::DescriptorImageInfo imageInfo( + nullptr, + imageManager.getVulkanImageView(write.image, write.mipLevel + i), + layout + ); + + imageInfos.push_back(imageInfo); + } WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size(), + imageInfos.size() + 1 - write.mipCount, 0, write.binding, write.arrayIndex, + write.mipCount, vk::DescriptorType::eSampledImage, }; @@ -202,19 +210,22 @@ namespace vkcv } for (const auto& write : writes.getStorageImageWrites()) { - const vk::DescriptorImageInfo imageInfo( - nullptr, - imageManager.getVulkanImageView(write.image, write.mipLevel), - vk::ImageLayout::eGeneral - ); - - imageInfos.push_back(imageInfo); + for (uint32_t i = 0; i < write.mipCount; i++) { + const vk::DescriptorImageInfo imageInfo( + nullptr, + imageManager.getVulkanImageView(write.image, write.mipLevel + i), + vk::ImageLayout::eGeneral + ); + + imageInfos.push_back(imageInfo); + } WriteDescriptorSetInfo vulkanWrite = { - imageInfos.size(), + imageInfos.size() + 1 - write.mipCount, 0, write.binding, 0, + write.mipCount, vk::DescriptorType::eStorageImage }; @@ -240,6 +251,7 @@ namespace vkcv bufferInfos.size(), write.binding, 0, + 1, write.dynamic? vk::DescriptorType::eUniformBufferDynamic : vk::DescriptorType::eUniformBuffer @@ -267,6 +279,7 @@ namespace vkcv bufferInfos.size(), write.binding, 0, + 1, write.dynamic? vk::DescriptorType::eStorageBufferDynamic : vk::DescriptorType::eStorageBuffer @@ -291,6 +304,7 @@ namespace vkcv 0, write.binding, 0, + 1, vk::DescriptorType::eSampler }; @@ -304,7 +318,7 @@ namespace vkcv set, write.binding, write.arrayElementIndex, - 1, + write.descriptorCount, write.type, (write.imageInfoIndex > 0? &(imageInfos[write.imageInfoIndex - 1]) : nullptr), (write.bufferInfoIndex > 0? &(bufferInfos[write.bufferInfoIndex - 1]) : nullptr) diff --git a/src/vkcv/DescriptorWrites.cpp b/src/vkcv/DescriptorWrites.cpp index 2dbf1b253d45c32ee1d7883aa0363c5640d023bb..68333b452cb5cef59a115812df17c2f89d06332e 100644 --- a/src/vkcv/DescriptorWrites.cpp +++ b/src/vkcv/DescriptorWrites.cpp @@ -7,15 +7,17 @@ namespace vkcv { ImageHandle image, uint32_t mipLevel, bool useGeneralLayout, - uint32_t arrayIndex) { - m_sampledImageWrites.emplace_back(binding, image, mipLevel, useGeneralLayout, arrayIndex); + uint32_t arrayIndex, + uint32_t mipCount) { + m_sampledImageWrites.emplace_back(binding, image, mipLevel, useGeneralLayout, arrayIndex, mipCount); return *this; } DescriptorWrites &DescriptorWrites::writeStorageImage(uint32_t binding, ImageHandle image, - uint32_t mipLevel) { - m_storageImageWrites.emplace_back(binding, image, mipLevel); + uint32_t mipLevel, + uint32_t mipCount) { + m_storageImageWrites.emplace_back(binding, image, mipLevel, mipCount); return *this; } diff --git a/src/vkcv/Downsampler.cpp b/src/vkcv/Downsampler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a857eec3f12af6fca2d05d598c357988ffce5114 --- /dev/null +++ b/src/vkcv/Downsampler.cpp @@ -0,0 +1,9 @@ + +#include "vkcv/Downsampler.hpp" + +namespace vkcv { + + Downsampler::Downsampler(Core& core) + : m_core(core) {} + +} diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp index af4426252d840bdffd7d210d900be64d6b74f6f3..bfceeb6300ece6dd3387d0785d8611a7289aa82c 100644 --- a/src/vkcv/FeatureManager.cpp +++ b/src/vkcv/FeatureManager.cpp @@ -576,4 +576,5 @@ m_physicalDevice.getFeatures2(&query) const vk::PhysicalDeviceFeatures2& FeatureManager::getFeatures() const { return m_featuresBase; } + } diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp index 15a2fc5240176742f50141407a3c72b531757ee9..32cbb05634bb3850c8071ab6a91e66bb85f29ba8 100644 --- a/src/vkcv/Image.cpp +++ b/src/vkcv/Image.cpp @@ -4,6 +4,8 @@ * @brief class for image handles */ #include "vkcv/Image.hpp" + +#include "vkcv/Downsampler.hpp" #include "ImageManager.hpp" namespace vkcv{ @@ -68,12 +70,9 @@ namespace vkcv{ m_manager->fillImage(m_handle, data, size); } - void Image::generateMipChainImmediate() { - m_manager->generateImageMipChainImmediate(m_handle); - } - - void Image::recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream) { - m_manager->recordImageMipChainGenerationToCmdStream(cmdStream, m_handle); + void Image::recordMipChainGeneration(const vkcv::CommandStreamHandle& cmdStream, + const Downsampler &downsampler) { + downsampler.recordDownsampling(cmdStream, m_handle); } Image::Image(ImageManager* manager, const ImageHandle& handle) : diff --git a/src/vkcv/ImageLayoutTransitions.cpp b/src/vkcv/ImageLayoutTransitions.cpp deleted file mode 100644 index 14b226847a15b5e9cadffc28555e76b88b61e6a3..0000000000000000000000000000000000000000 --- a/src/vkcv/ImageLayoutTransitions.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "ImageLayoutTransitions.hpp" -#include "vkcv/Image.hpp" - -namespace vkcv { - vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image &image, vk::ImageLayout newLayout) { - - vk::ImageAspectFlags aspectFlags; - if (isDepthFormat(image.m_format)) { - aspectFlags = vk::ImageAspectFlagBits::eDepth; - } - else { - aspectFlags = vk::ImageAspectFlagBits::eColor; - } - - vk::ImageSubresourceRange imageSubresourceRange( - aspectFlags, - 0, - image.m_viewPerMip.size(), - 0, - image.m_layers - ); - - // TODO: precise AccessFlagBits, will require a lot of context - return vk::ImageMemoryBarrier( - vk::AccessFlagBits::eMemoryWrite, - vk::AccessFlagBits::eMemoryRead, - image.m_layout, - newLayout, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - image.m_handle, - imageSubresourceRange); - } - - vk::ImageMemoryBarrier createSwapchainImageLayoutTransitionBarrier( - vk::Image vulkanHandle, - vk::ImageLayout oldLayout, - vk::ImageLayout newLayout) { - - vk::ImageSubresourceRange imageSubresourceRange( - vk::ImageAspectFlagBits::eColor, - 0, - 1, - 0, - 1); - - // TODO: precise AccessFlagBits, will require a lot of context - return vk::ImageMemoryBarrier( - vk::AccessFlagBits::eMemoryWrite, - vk::AccessFlagBits::eMemoryRead, - oldLayout, - newLayout, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - vulkanHandle, - imageSubresourceRange); - } - - void recordImageBarrier(vk::CommandBuffer cmdBuffer, vk::ImageMemoryBarrier barrier) { - cmdBuffer.pipelineBarrier( - vk::PipelineStageFlagBits::eAllCommands, - vk::PipelineStageFlagBits::eAllCommands, - {}, - nullptr, - nullptr, - barrier); - } -} \ No newline at end of file diff --git a/src/vkcv/ImageLayoutTransitions.hpp b/src/vkcv/ImageLayoutTransitions.hpp deleted file mode 100644 index 5c147f133a6492746ad410367e5e627be000d7be..0000000000000000000000000000000000000000 --- a/src/vkcv/ImageLayoutTransitions.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include <vulkan/vulkan.hpp> -#include "ImageManager.hpp" - -namespace vkcv { - vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image& image, vk::ImageLayout newLayout); - vk::ImageMemoryBarrier createSwapchainImageLayoutTransitionBarrier( - vk::Image vulkanHandle, - vk::ImageLayout oldLayout, - vk::ImageLayout newLayout); - - void recordImageBarrier(vk::CommandBuffer cmdBuffer, vk::ImageMemoryBarrier barrier); -} \ No newline at end of file diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index bfee504f599d941e625e6ef5c6045805c33a29a1..e7112579c7316ca8f886c66a63cdf74749a287a9 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -5,7 +5,6 @@ */ #include "ImageManager.hpp" #include "vkcv/Core.hpp" -#include "ImageLayoutTransitions.hpp" #include "vkcv/Logger.hpp" #include <algorithm> @@ -276,6 +275,46 @@ namespace vkcv { return image.m_viewPerMip[mipLevel]; } + static vk::ImageMemoryBarrier createImageLayoutTransitionBarrier(const ImageManager::Image &image, + uint32_t mipLevelCount, + uint32_t mipLevelOffset, + vk::ImageLayout newLayout) { + vk::ImageAspectFlags aspectFlags; + if (isDepthFormat(image.m_format)) { + aspectFlags = vk::ImageAspectFlagBits::eDepth; + } else { + aspectFlags = vk::ImageAspectFlagBits::eColor; + } + + const uint32_t mipLevelsMax = image.m_viewPerMip.size(); + + if (mipLevelOffset > mipLevelsMax) + mipLevelOffset = mipLevelsMax; + + if ((!mipLevelCount) || (mipLevelOffset + mipLevelCount > mipLevelsMax)) + mipLevelCount = mipLevelsMax - mipLevelOffset; + + vk::ImageSubresourceRange imageSubresourceRange( + aspectFlags, + mipLevelOffset, + mipLevelCount, + 0, + image.m_layers + ); + + // TODO: precise AccessFlagBits, will require a lot of context + return vk::ImageMemoryBarrier( + vk::AccessFlagBits::eMemoryWrite, + vk::AccessFlagBits::eMemoryRead, + image.m_layout, + newLayout, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + image.m_handle, + imageSubresourceRange + ); + } + void ImageManager::switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout) { uint64_t id = handle.getId(); @@ -287,7 +326,7 @@ namespace vkcv { } auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - const auto transitionBarrier = createImageLayoutTransitionBarrier(image, newLayout); + const auto transitionBarrier = createImageLayoutTransitionBarrier(image, 0, 0, newLayout); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Graphics; @@ -309,11 +348,11 @@ namespace vkcv { image.m_layout = newLayout; } - void ImageManager::recordImageLayoutTransition( - const ImageHandle& handle, - vk::ImageLayout newLayout, - vk::CommandBuffer cmdBuffer) { - + void ImageManager::recordImageLayoutTransition(const ImageHandle& handle, + uint32_t mipLevelCount, + uint32_t mipLevelOffset, + vk::ImageLayout newLayout, + vk::CommandBuffer cmdBuffer) { const uint64_t id = handle.getId(); const bool isSwapchainImage = handle.isSwapchainImage(); @@ -323,8 +362,22 @@ namespace vkcv { } auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - const auto transitionBarrier = createImageLayoutTransitionBarrier(image, newLayout); - recordImageBarrier(cmdBuffer, transitionBarrier); + const auto transitionBarrier = createImageLayoutTransitionBarrier( + image, + mipLevelCount, + mipLevelOffset, + newLayout + ); + + cmdBuffer.pipelineBarrier( + vk::PipelineStageFlagBits::eAllCommands, + vk::PipelineStageFlagBits::eAllCommands, + {}, + nullptr, + nullptr, + transitionBarrier + ); + image.m_layout = newLayout; } @@ -341,8 +394,16 @@ namespace vkcv { } auto& image = isSwapchainImage ? m_swapchainImages[m_currentSwapchainInputImage] : m_images[id]; - const auto transitionBarrier = createImageLayoutTransitionBarrier(image, image.m_layout); - recordImageBarrier(cmdBuffer, transitionBarrier); + const auto transitionBarrier = createImageLayoutTransitionBarrier(image, 0, 0, image.m_layout); + + cmdBuffer.pipelineBarrier( + vk::PipelineStageFlagBits::eAllCommands, + vk::PipelineStageFlagBits::eAllCommands, + {}, + nullptr, + nullptr, + transitionBarrier + ); } constexpr uint32_t getBytesPerPixel(vk::Format format) { @@ -452,7 +513,7 @@ namespace vkcv { } auto& image = m_images[id]; - recordImageLayoutTransition(handle, vk::ImageLayout::eGeneral, cmdBuffer); + recordImageLayoutTransition(handle, 0, 0, vk::ImageLayout::eGeneral, cmdBuffer); vk::ImageAspectFlags aspectMask = isDepthImageFormat(image.m_format) ? vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor; @@ -497,22 +558,6 @@ namespace vkcv { } } - void ImageManager::generateImageMipChainImmediate(const ImageHandle& handle) { - SubmitInfo submitInfo; - submitInfo.queueType = QueueType::Graphics; - - if (handle.isSwapchainImage()) { - vkcv_log(vkcv::LogLevel::ERROR, "You cannot generate a mip chain for the swapchain, what are you smoking?"); - return; - } - - const auto record = [this, handle](const vk::CommandBuffer cmdBuffer) { - recordImageMipGenerationToCmdBuffer(cmdBuffer, handle); - }; - - m_core->recordAndSubmitCommandsImmediate(submitInfo, record, nullptr); - } - void ImageManager::recordImageMipChainGenerationToCmdStream( const vkcv::CommandStreamHandle& cmdStream, const ImageHandle& handle) { @@ -549,8 +594,8 @@ namespace vkcv { vk::Offset3D(0, 0, 0), vk::Extent3D(dstImage.m_width, dstImage.m_height, dstImage.m_depth)); - recordImageLayoutTransition(src, vk::ImageLayout::eTransferSrcOptimal, cmdBuffer); - recordImageLayoutTransition(dst, vk::ImageLayout::eTransferDstOptimal, cmdBuffer); + recordImageLayoutTransition(src, 0, 0, vk::ImageLayout::eTransferSrcOptimal, cmdBuffer); + recordImageLayoutTransition(dst, 0, 0, vk::ImageLayout::eTransferDstOptimal, cmdBuffer); cmdBuffer.resolveImage( srcImage.m_handle, diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index aedf726031ef43ac723b93f3dbd1276d92f3f704..5ac21b55a37d657929d409415b62013590bbb78f 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -97,8 +97,11 @@ namespace vkcv { vk::ImageView getVulkanImageView(const ImageHandle& handle, size_t mipLevel = 0) const; void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout); + void recordImageLayoutTransition( - const ImageHandle& handle, + const ImageHandle& handle, + uint32_t mipLevelCount, + uint32_t mipLevelOffset, vk::ImageLayout newLayout, vk::CommandBuffer cmdBuffer); @@ -107,7 +110,6 @@ namespace vkcv { vk::CommandBuffer cmdBuffer); void fillImage(const ImageHandle& handle, const void* data, size_t size); - void generateImageMipChainImmediate(const ImageHandle& handle); void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, const ImageHandle& handle); void recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst);