diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index e8ce984d7daa945c5436c51e896e797a0da22b84..a11db52fdc2c6a8bdc1668110539dffb9c23e6de 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -300,41 +300,54 @@ namespace vkcv Swapchain& getSwapchain(const WindowHandle &handle); /** - * Returns the image width - * @param image handle + * @brief Returns the image width. + * + * @param image Image handle * @return imageWidth */ [[nodiscard]] uint32_t getImageWidth(const ImageHandle &image); /** - * Returns the image height - * @param image handle + * @brief Returns the image height. + * + * @param[in] image Image handle * @return imageHeight */ [[nodiscard]] uint32_t getImageHeight(const ImageHandle &image); /** - * Returns the image depth - * @param image handle + * @brief Returns the image depth. + * + * @param[in] image Image handle * @return imageDepth */ [[nodiscard]] uint32_t getImageDepth(const ImageHandle &image); /** - * Returns the image format of the image - * @param image handle + * @brief Returns the image format of the image. + * + * @param[in] image Image handle * @return imageFormat */ [[nodiscard]] vk::Format getImageFormat(const ImageHandle &image); + + /** + * @brief Returns whether the image supports storage or not. + * + * @param[in] image Image handle + * @return True, if the image supports storage, otherwise false. + */ + [[nodiscard]] + bool isImageSupportingStorage(const ImageHandle& image); /** * @brief Returns the images amount of mip levels. * - * @param image Image handle + * @param[in] image Image handle * @return Amount of mip levels */ [[nodiscard]] @@ -343,7 +356,7 @@ namespace vkcv /** * @brief Returns the images amount of array layers. * - * @param image Image handle + * @param[in] image Image handle * @return Amount of array layers */ [[nodiscard]] @@ -352,7 +365,7 @@ namespace vkcv /** * @brief Creates a descriptor set layout handle by a set of descriptor bindings. * - * @param bindings Descriptor bindings + * @param[in] bindings Descriptor bindings * @return Descriptor set layout handle */ [[nodiscard]] @@ -361,7 +374,7 @@ namespace vkcv /** * @brief Returns the descriptor set layout of a descriptor set layout handle. * - * @param handle Descriptor set layout handle + * @param[in] handle Descriptor set layout handle * @return Descriptor set layout */ DescriptorSetLayout getDescriptorSetLayout(const DescriptorSetLayoutHandle handle) const; @@ -369,11 +382,11 @@ namespace vkcv /** * @brief Creates a new descriptor set * - * @param layoutHandle Handle to the layout that the descriptor set will use + * @param[in] layout Handle to the layout that the descriptor set will use * @return Handle that represents the descriptor set */ [[nodiscard]] - DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layoutHandle); + DescriptorSetHandle createDescriptorSet(const DescriptorSetLayoutHandle &layout); /** * @brief Writes resources bindings to a descriptor set diff --git a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp index fb078cc9cca080d77932422de9a86a4876de249b..ea6331b022437dcb7eb623bd268467e7deca1e8f 100644 --- a/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp +++ b/modules/algorithm/src/vkcv/algorithm/SinglePassDownsampler.cpp @@ -234,7 +234,7 @@ namespace vkcv::algorithm { m_core.prepareImageForSampling(cmdStream, image); - if ((mipLevels < 4) || (depth > 1)) { + if ((mipLevels < 4) || (depth > 1) || (!m_core.isImageSupportingStorage(image))) { m_core.getDownsampler().recordDownsampling(cmdStream, image); return; } diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp index a6a16f80aab9f6baf610cd550f1cbd205795cf4e..8c3f3099cee731d24854d314fd7e3df4506a9aec 100644 --- a/modules/material/src/vkcv/material/Material.cpp +++ b/modules/material/src/vkcv/material/Material.cpp @@ -119,21 +119,21 @@ namespace vkcv::material { } if (!normalImg) { - vkcv::Image defaultNormal = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); + vkcv::Image defaultNormal = core.createImage(vk::Format::eR8G8B8A8Unorm, 2, 2); float normalData [4] = { 0, 0, 1, 0 }; fillImage(defaultNormal, normalData); images[1] = defaultNormal.getHandle(); } if (!metRoughImg) { - vkcv::Image defaultRough = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); + vkcv::Image defaultRough = core.createImage(vk::Format::eR8G8B8A8Unorm, 2, 2); float roughData [4] = { 228, 51, 255, 1 }; fillImage(defaultRough, roughData); images[2] = defaultRough.getHandle(); } if (!occlusionImg) { - vkcv::Image defaultOcclusion = core.createImage(vk::Format::eR8G8B8A8Srgb, 2, 2); + vkcv::Image defaultOcclusion = core.createImage(vk::Format::eR8G8B8A8Unorm, 2, 2); float occlusionData [4] = { 228, 51, 255, 1 }; fillImage(defaultOcclusion, occlusionData); images[3] = defaultOcclusion.getHandle(); diff --git a/modules/scene/CMakeLists.txt b/modules/scene/CMakeLists.txt index 08a7e59074728a6429949da2c39f2d9e169b6928..39effd0f802bb9d8ef4b318d5f1d233fa93db492 100644 --- a/modules/scene/CMakeLists.txt +++ b/modules/scene/CMakeLists.txt @@ -36,13 +36,24 @@ add_library(vkcv_scene ${vkcv_build_attribute} ${vkcv_scene_sources}) target_link_libraries(vkcv_scene vkcv) # including headers of dependencies and the VkCV framework -target_include_directories(vkcv_scene SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_material_include} ${vkcv_camera_include}) +target_include_directories(vkcv_scene SYSTEM BEFORE PRIVATE + ${vkcv_include} + ${vkcv_includes} + ${vkcv_asset_loader_include} + ${vkcv_material_include} + ${vkcv_camera_include} + ${vkcv_algorithm_include}) # add the own include directory for public headers target_include_directories(vkcv_scene BEFORE PUBLIC ${vkcv_scene_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(vkcv_scene vkcv vkcv_asset_loader vkcv_material vkcv_camera) +target_link_libraries(vkcv_scene + vkcv + vkcv_asset_loader + vkcv_material + vkcv_camera + vkcv_algorithm) if (vkcv_parent_scope) list(APPEND vkcv_modules_includes ${vkcv_scene_include}) diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp index bb21807d72d63ded8b2aa538414a4694babbfe05..cb8193708efcac7eb5e614353aa0b30101078833 100644 --- a/modules/scene/src/vkcv/scene/Scene.cpp +++ b/modules/scene/src/vkcv/scene/Scene.cpp @@ -4,6 +4,8 @@ #include <vkcv/Logger.hpp> #include <vkcv/asset/asset_loader.hpp> +#include <vkcv/algorithm/SinglePassDownsampler.hpp> + namespace vkcv::scene { Scene::Scene(Core* core) : @@ -274,10 +276,34 @@ namespace vkcv::scene { scene.getNode(root).loadMesh(asset_scene, mesh); } + vkcv::SamplerHandle sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + const vkcv::FeatureManager& featureManager = core.getContext().getFeatureManager(); + const bool partialBound = featureManager.checkFeatures<vk::PhysicalDeviceDescriptorIndexingFeatures>( + vk::StructureType::ePhysicalDeviceDescriptorIndexingFeatures, + [](const vk::PhysicalDeviceDescriptorIndexingFeatures& features) { + return features.descriptorBindingPartiallyBound; + } + ); + + vkcv::Downsampler& downsampler = core.getDownsampler(); + vkcv::algorithm::SinglePassDownsampler spdDownsampler (core, sampler); + auto mipStream = core.createCommandStream(vkcv::QueueType::Graphics); - for (auto& material : scene.m_materials) { - material.m_data.recordMipChainGeneration(mipStream, core.getDownsampler()); + if (partialBound) { + for (auto& material : scene.m_materials) { + material.m_data.recordMipChainGeneration(mipStream, spdDownsampler); + } + } else { + for (auto& material : scene.m_materials) { + material.m_data.recordMipChainGeneration(mipStream, downsampler); + } } core.submitCommandStream(mipStream, false); diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 3c4f51bb119f585e449aa48de2aef086d0789dd7..b09943e4b9432ac09c6eaaa5bbe06b0b28b59ab3 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -7,18 +7,28 @@ #include <vkcv/asset/asset_loader.hpp> #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/scene/Scene.hpp> +#include <vkcv/Features.hpp> int main(int argc, const char** argv) { const char* applicationName = "First Scene"; uint32_t windowWidth = 800; uint32_t windowHeight = 600; + + vkcv::Features features; + features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + features.requireExtensionFeature<vk::PhysicalDeviceDescriptorIndexingFeatures>( + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, + [](vk::PhysicalDeviceDescriptorIndexingFeatures& features) { + features.setDescriptorBindingPartiallyBound(true); + } + ); vkcv::Core core = vkcv::Core::create( applicationName, VK_MAKE_VERSION(0, 0, 1), {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, - { VK_KHR_SWAPCHAIN_EXTENSION_NAME } + features ); vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, true); vkcv::Window& window = core.getWindow(windowHandle); diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index 4aa285deb81ead2e078fb59f3c59e852fb6c4627..fe096114ead0b66a6d919a4d49baa791debc4897 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -291,7 +291,7 @@ 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().recordMipChainGeneration(mipStream, downsampler); + sceneImages.back().recordMipChainGeneration(mipStream, spdDownsampler); const vkcv::ImageHandle albedoHandle = sceneImages.back().getHandle(); // normal texture diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 808e0c68407fdd6a2f5dd1df962af01f82c760a1..06942b87c072566120d4397f3d3be728770ae057 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -900,6 +900,10 @@ namespace vkcv return m_ImageManager->getImageFormat(image); } + bool Core::isImageSupportingStorage(const ImageHandle &image) { + return m_ImageManager->isImageSupportingStorage(image); + } + uint32_t Core::getImageMipLevels(const ImageHandle &image) { return m_ImageManager->getImageMipCount(image); } @@ -931,9 +935,9 @@ namespace vkcv return m_DescriptorManager->getDescriptorSetLayout(handle); } - DescriptorSetHandle Core::createDescriptorSet(const DescriptorSetLayoutHandle &layoutHandle) + DescriptorSetHandle Core::createDescriptorSet(const DescriptorSetLayoutHandle &layout) { - return m_DescriptorManager->createDescriptorSet(layoutHandle); + return m_DescriptorManager->createDescriptorSet(layout); } void Core::writeDescriptorSet(DescriptorSetHandle handle, const DescriptorWrites &writes) { diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index b58fe3c56a60d3ba619b1d11859271dd198bc6b7..d37e293b48c2c6fc39cab6afd9cfc5054aebcb73 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -92,6 +92,9 @@ namespace vkcv { if (!(formatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eStorageImage)) { imageTiling = vk::ImageTiling::eLinear; + + if (!(formatProperties.linearTilingFeatures & vk::FormatFeatureFlagBits::eStorageImage)) + return ImageHandle(); } } @@ -253,7 +256,8 @@ namespace vkcv { format, arrayLayers, - vk::ImageLayout::eUndefined + vk::ImageLayout::eUndefined, + supportStorage }); return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); }); @@ -750,6 +754,22 @@ namespace vkcv { return isSwapchainFormat ? m_swapchainImages[m_currentSwapchainInputImage].m_format : m_images[id].m_format; } + + bool ImageManager::isImageSupportingStorage(const ImageHandle& handle) const { + const uint64_t id = handle.getId(); + const bool isSwapchainFormat = handle.isSwapchainImage(); + + if (isSwapchainFormat) { + return false; + } + + if (id >= m_images.size()) { + vkcv_log(LogLevel::ERROR, "Invalid handle"); + return false; + } + + return m_images[id].m_storage; + } uint32_t ImageManager::getImageMipCount(const ImageHandle& handle) const { const uint64_t id = handle.getId(); @@ -808,7 +828,8 @@ namespace vkcv { 1, format, 1, - vk::ImageLayout::eUndefined + vk::ImageLayout::eUndefined, + false }); } } diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index 84d41d3457d1d5a2869f08ba1401ddc3decbbc26..3e577fd9a61fea6334faaf136386bf845ca387e8 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -46,6 +46,7 @@ namespace vkcv { vk::Format m_format; uint32_t m_layers; vk::ImageLayout m_layout; + bool m_storage; private: friend ImageManager; }; @@ -130,6 +131,9 @@ namespace vkcv { [[nodiscard]] vk::Format getImageFormat(const ImageHandle& handle) const; + + [[nodiscard]] + bool isImageSupportingStorage(const ImageHandle& handle) const; [[nodiscard]] uint32_t getImageMipCount(const ImageHandle& handle) const;