diff --git a/config/Sources.cmake b/config/Sources.cmake index db4b200fa99597af4f96432e35e80af387ae881a..6cf9c6f4663c4307ee6c9350941cbe6e2f2b5a2c 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -41,6 +41,9 @@ set(vkcv_sources ${vkcv_source}/vkcv/BufferManager.hpp ${vkcv_source}/vkcv/BufferManager.cpp + + ${vkcv_include}/vkcv/ImageConfig.hpp + ${vkcv_source}/vkcv/ImageConfig.cpp ${vkcv_include}/vkcv/Image.hpp ${vkcv_source}/vkcv/Image.cpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 1a4ce7c8ca203661d6bb21fdfbde0beb8ac02b12..fc80436ec85967619dab6aa5a518f0986e2b4f62 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -21,6 +21,7 @@ #include "EventFunctionTypes.hpp" #include "GraphicsPipelineConfig.hpp" #include "Handles.hpp" +#include "ImageConfig.hpp" #include "PassConfig.hpp" #include "PushConstants.hpp" #include "Result.hpp" @@ -318,24 +319,17 @@ namespace vkcv { SamplerBorderColor borderColor = SamplerBorderColor::INT_ZERO_OPAQUE); /** - * Creates an #Image with a given format, width, height, depth - * and a lot more optional parameters. + * Creates an #Image with a given format, configuration + * and whether a mipchain should be created. * * @param[in] format Image format - * @param[in] width Image width - * @param[in] height Image height - * @param[in] depth Image depth + * @param[in] config Image configuration * @param[in] createMipChain Flag to create a mip chain - * @param[in] supportStorage Flag whether support storage - * @param[in] supportColorAttachment Flag whether attachment is supported - * @param[in] multisampling Multisampling * @return Image handle */ - [[nodiscard]] ImageHandle createImage(vk::Format format, uint32_t width, uint32_t height, - uint32_t depth = 1, bool createMipChain = false, - bool supportStorage = false, - bool supportColorAttachment = false, - Multisampling multisampling = Multisampling::None); + [[nodiscard]] ImageHandle createImage(vk::Format format, + const ImageConfig& config, + bool createMipChain = false); /** * @brief Fills the image with given data of a specified size diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index 69d4bc07e7f40af3d5d2802dd06576f166329427..511ac67102ec26e9bd92c1b9e62b42d34c784e4d 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -10,6 +10,7 @@ #include "BufferTypes.hpp" #include "Core.hpp" #include "Handles.hpp" +#include "ImageConfig.hpp" #include "Multisampling.hpp" namespace vkcv { @@ -131,5 +132,10 @@ namespace vkcv { bool createMipChain = false, bool supportStorage = false, bool supportColorAttachment = false, Multisampling multisampling = Multisampling::None); + + Image image(Core &core, + vk::Format format, + const ImageConfig &config, + bool createMipChain = false); } // namespace vkcv diff --git a/include/vkcv/ImageConfig.hpp b/include/vkcv/ImageConfig.hpp new file mode 100644 index 0000000000000000000000000000000000000000..21e9f6d05ac254e90e29d670304df961099cecef --- /dev/null +++ b/include/vkcv/ImageConfig.hpp @@ -0,0 +1,160 @@ +#pragma once +/** + * @authors Tobias Frisch + * @file vkcv/ImageConfig.hpp + * @brief Structure for image configuration. + */ + +#include "Multisampling.hpp" + +namespace vkcv { + + struct ImageConfig { + private: + uint32_t m_width; + uint32_t m_height; + uint32_t m_depth; + + bool m_supportStorage; + bool m_supportColorAttachment; + bool m_cubeMapImage; + + Multisampling m_msaa; + + public: + /** + * Constructor of the image configuration by + * a given resolution. + * + * @param[in] width Image width + * @param[in] height Image height + * @param[in] depth Image depth + */ + ImageConfig(uint32_t width, + uint32_t height, + uint32_t depth = 1); + + ImageConfig(const ImageConfig &other) = default; + ImageConfig(ImageConfig&& other) = default; + + ~ImageConfig() = default; + + ImageConfig& operator=(const ImageConfig &other) = default; + ImageConfig& operator=(ImageConfig&& other) = default; + + /** + * Return the configured width of the image. + * + * @return Image width + */ + [[nodiscard]] + uint32_t getWidth() const; + + /** + * Set configured width of the image. + * + * @param[in] width Image width + */ + void setWidth(uint32_t width); + + /** + * Return the configured height of the image. + * + * @return Image height + */ + [[nodiscard]] + uint32_t getHeight() const; + + /** + * Set configured height of the image. + * + * @param[in] height Image height + */ + void setHeight(uint32_t height); + + /** + * Return the configured depth of the image. + * + * @return Image depth + */ + [[nodiscard]] + uint32_t getDepth() const; + + /** + * Set configured depth of the image. + * + * @param[in] depth Image depth + */ + void setDepth(uint32_t depth); + + /** + * Return whether the image is configured to + * support storage operations. + * + * @return True, if it supports storage, otherwise false + */ + [[nodiscard]] + bool isSupportingStorage() const; + + /** + * Set whether the image is configured to + * support storage operations. + * + * @param[in] supportStorage Support storage + */ + void setSupportingStorage(bool supportStorage); + + /** + * Return whether the image is configured to + * support being used as color attachment. + * + * @return True, if it supports color attachment, otherwise false + */ + [[nodiscard]] + bool isSupportingColorAttachment() const; + + /** + * Set whether the image is configured to + * support being used as color attachment. + * + * @param[in] supportColorAttachment Support color attachment + */ + void setSupportingColorAttachment(bool supportColorAttachment); + + /** + * Return whether the image is configured to + * be a cube map. + * + * @return True, if the image is a cube map, otherwise false + */ + [[nodiscard]] + bool isCubeMapImage() const; + + /** + * Set whether the image is configured to + * be a cube map. + * + * @param[in] cubeMapImage Is cube map image + */ + void setCubeMapImage(bool cubeMapImage); + + /** + * Return type of multisampling the image + * is configured to use. + * + * @return Multisampling + */ + [[nodiscard]] + Multisampling getMultisampling() const; + + /** + * Set the multisampling of the image + * configuration. + * + * @param[in] msaa Multisampling + */ + void setMultisampling(Multisampling msaa); + + }; + +} diff --git a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp index f31596ae80c86a432f62a50621de949961e83d56..133b380095abc6c729ef94da675cc9f394475ab4 100644 --- a/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp +++ b/modules/effects/src/vkcv/effects/BloomAndFlaresEffect.cpp @@ -294,7 +294,7 @@ namespace vkcv::effects { cmdStream, m_downsamplePipeline, dispatch, - { DescriptorSetUsage(0, mipDescriptorSets[mipLevel]) }, + { useDescriptorSet(0, mipDescriptorSets[mipLevel]) }, PushConstants(0) ); @@ -342,7 +342,7 @@ namespace vkcv::effects { cmdStream, m_upsamplePipeline, dispatch, - { DescriptorSetUsage(0, mipDescriptorSets[mipLevel - 1]) }, + { useDescriptorSet(0, mipDescriptorSets[mipLevel - 1]) }, PushConstants(0) ); @@ -388,7 +388,7 @@ namespace vkcv::effects { cmdStream, m_lensFlaresPipeline, dispatch, - { DescriptorSetUsage(0, m_lensFlaresDescriptorSet) }, + { useDescriptorSet(0, m_lensFlaresDescriptorSet) }, PushConstants(0) ); } @@ -455,7 +455,7 @@ namespace vkcv::effects { cmdStream, m_compositePipeline, dispatch, - { DescriptorSetUsage(0, m_compositeDescriptorSet) }, + { useDescriptorSet(0, m_compositeDescriptorSet) }, m_advanced? pushConstants : PushConstants(0) ); } @@ -475,15 +475,15 @@ namespace vkcv::effects { static_cast<float>(m_core.getImageHeight(output)) * 0.5f )); + vkcv::ImageConfig imageConfig (halfWidth, halfHeight); + imageConfig.setSupportingStorage(true); + if ((!m_blurImage) || (halfWidth != m_core.getImageWidth(m_blurImage)) || (halfHeight != m_core.getImageHeight(m_blurImage))) { m_blurImage = m_core.createImage( m_core.getImageFormat(output), - halfWidth, - halfHeight, - 1, - true, + imageConfig, true ); @@ -510,10 +510,7 @@ namespace vkcv::effects { (halfHeight != m_core.getImageHeight(m_flaresImage))) { m_flaresImage = m_core.createImage( m_core.getImageFormat(output), - halfWidth, - halfHeight, - 1, - true, + imageConfig, true ); diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp index 247161e35718cde352da5461b51f30c4fe8570c7..bacb4ce0814ff0caec0c3d4d353ecf5019e0eda4 100644 --- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp +++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp @@ -274,11 +274,12 @@ namespace vkcv::upscaling { if ((!m_intermediateImage) || (outputWidth != m_core.getImageWidth(m_intermediateImage)) || (outputHeight != m_core.getImageHeight(m_intermediateImage))) { + ImageConfig imageConfig (outputWidth, outputHeight); + imageConfig.setSupportingStorage(true); + m_intermediateImage = m_core.createImage( m_core.getImageFormat(output), - outputWidth, outputHeight,1, - false, - true + imageConfig ); m_core.prepareImageForStorage(cmdStream, m_intermediateImage); @@ -333,7 +334,7 @@ namespace vkcv::upscaling { cmdStream, m_easuPipeline, dispatch, - {DescriptorSetUsage(0, m_easuDescriptorSet, { 0 })}, + { useDescriptorSet(0, m_easuDescriptorSet, { 0 }) }, PushConstants(0) ); @@ -353,7 +354,7 @@ namespace vkcv::upscaling { cmdStream, m_rcasPipeline, dispatch, - {DescriptorSetUsage(0,m_rcasDescriptorSet, { 0 })}, + { useDescriptorSet(0,m_rcasDescriptorSet, { 0 }) }, PushConstants(0) ); @@ -371,7 +372,7 @@ namespace vkcv::upscaling { cmdStream, m_easuPipeline, dispatch, - {DescriptorSetUsage(0, m_easuDescriptorSet, { 0 })}, + { useDescriptorSet(0, m_easuDescriptorSet, { 0 }) }, PushConstants(0) ); } diff --git a/projects/bindless_textures/src/main.cpp b/projects/bindless_textures/src/main.cpp index 42af6910cd0102f01df29d470269882ebd1cb0d0..37d0c68b34eeb45560907fc43d049d61f0285c17 100644 --- a/projects/bindless_textures/src/main.cpp +++ b/projects/bindless_textures/src/main.cpp @@ -185,9 +185,7 @@ int main(int argc, const char** argv) { vkcv::SamplerHandle sampler = vkcv::samplerLinear(core); vkcv::DescriptorWrites setWrites; - for(uint32_t i = 0; i < 6; i++) - { - + for(uint32_t i = 0; i < 6; i++) { setWrites.writeSampledImage( 1, texturesArray[i].getHandle(), @@ -225,8 +223,7 @@ int main(int argc, const char** argv) { (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig(swapchainWidth, swapchainHeight) ); } diff --git a/projects/fire_works/src/main.cpp b/projects/fire_works/src/main.cpp index 472b781905fc446c592bef74bc0262792e8c3988..0166da4b5788990a05f85da5a3b41c0e206d956a 100644 --- a/projects/fire_works/src/main.cpp +++ b/projects/fire_works/src/main.cpp @@ -331,11 +331,17 @@ int main(int argc, const char **argv) { std::array<vkcv::ImageHandle, 4> colorBuffers; for (size_t i = 0; i < colorBuffers.size(); i++) { + vkcv::ImageConfig colorBufferConfig ( + swapchainExtent.width, + swapchainExtent.height + ); + + colorBufferConfig.setSupportingStorage(true); + colorBufferConfig.setSupportingColorAttachment(true); + colorBuffers[i] = core.createImage( colorFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true + colorBufferConfig ); } @@ -700,65 +706,60 @@ int main(int argc, const char **argv) { std::vector<uint32_t> zeroVoxel; zeroVoxel.resize(voxelWidth * voxelHeight * voxelDepth, 0); + vkcv::ImageConfig voxelImageConfig ( + voxelWidth, + voxelHeight, + voxelDepth + ); + + voxelImageConfig.setSupportingStorage(true); + vkcv::Image voxelRed = vkcv::image( core, vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + voxelImageConfig ); vkcv::Image voxelGreen = vkcv::image( core, vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + voxelImageConfig ); vkcv::Image voxelBlue = vkcv::image( core, vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + voxelImageConfig ); vkcv::Image voxelDensity = vkcv::image( core, vk::Format::eR32Uint, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + voxelImageConfig ); std::array<vkcv::ImageHandle, 2> voxelData { core.createImage( vk::Format::eR16G16B16A16Sfloat, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + voxelImageConfig ), core.createImage( vk::Format::eR16G16B16A16Sfloat, - voxelWidth, - voxelHeight, - voxelDepth, - false, true + voxelImageConfig ) }; + vkcv::ImageConfig voxelSamplesConfig ( + voxelWidth, + voxelHeight + ); + + voxelImageConfig.setSupportingStorage(true); + vkcv::Image voxelSamples = vkcv::image( core, colorFormat, - voxelWidth, - voxelHeight, - 1, false, true + voxelSamplesConfig ); vkcv::SamplerHandle voxelSampler = vkcv::samplerLinear(core, true); @@ -934,14 +935,20 @@ int main(int argc, const char **argv) { continue; } - for (size_t i = 0; i < colorBuffers.size(); i++) { - if ((core.getImageWidth(colorBuffers[i]) != swapchainWidth) || - (core.getImageHeight(colorBuffers[i]) != swapchainHeight)) { - colorBuffers[i] = core.createImage( + for (auto& colorBuffer : colorBuffers) { + if ((core.getImageWidth(colorBuffer) != swapchainWidth) || + (core.getImageHeight(colorBuffer) != swapchainHeight)) { + vkcv::ImageConfig colorBufferConfig ( + swapchainWidth, + swapchainHeight + ); + + colorBufferConfig.setSupportingStorage(true); + colorBufferConfig.setSupportingColorAttachment(true); + + colorBuffer = core.createImage( colorFormat, - swapchainWidth, - swapchainHeight, - 1, false, true, true + colorBufferConfig ); } } diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index 1350156140e4946599982a5057b2bab0bab276aa..ecb1d9791e764b8bc36515fa7a76def7ee25ca6c 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -117,8 +117,10 @@ int main(int argc, const char** argv) { (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); } diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 9fb7247ec6da805acd2312c3889c45e4a95a3d48..1d0fd0e989c4b41d0f08feaa7f4c8ae0b8fa3d3c 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -103,8 +103,10 @@ int main(int argc, const char** argv) { (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); } diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp index 1b6533cfdd3726ad8b1901ae5bbb800d5c65b81d..e96f22eb665e681e9d4e1b100ad47fa60df267f3 100644 --- a/projects/head_demo/src/main.cpp +++ b/projects/head_demo/src/main.cpp @@ -150,15 +150,23 @@ int main(int argc, const char** argv) { vkcv::ImageHandle depthBuffer = core.createImage( vk::Format::eD32Sfloat, + vkcv::ImageConfig( + swapchainExtent.width, + swapchainExtent.height + ) + ); + + vkcv::ImageConfig colorBufferConfig ( swapchainExtent.width, swapchainExtent.height ); + colorBufferConfig.setSupportingStorage(true); + colorBufferConfig.setSupportingColorAttachment(true); + vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true + colorBufferConfig ); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -168,14 +176,22 @@ int main(int argc, const char** argv) { core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, uint32_t swapchainWidth, uint32_t swapchainHeight) { - if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight); + if ((swapchainWidth != swapchainExtent.width) || + ((swapchainHeight != swapchainExtent.height))) { + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) + ); + + colorBufferConfig.setWidth(swapchainWidth); + colorBufferConfig.setHeight(swapchainHeight); colorBuffer = core.createImage( colorFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true + colorBufferConfig ); swapchainExtent.width = swapchainWidth; diff --git a/projects/indirect_dispatch/src/AppSetup.cpp b/projects/indirect_dispatch/src/AppSetup.cpp index 26cfbbc38e2a190326b8a17adde5b8e4f44ec1cc..0a334932defb8ea3632d4047a4ca8e66e91faa20 100644 --- a/projects/indirect_dispatch/src/AppSetup.cpp +++ b/projects/indirect_dispatch/src/AppSetup.cpp @@ -301,33 +301,24 @@ bool loadComputePass(vkcv::Core& core, const std::filesystem::path& path, Comput AppRenderTargets createRenderTargets(vkcv::Core& core, const uint32_t width, const uint32_t height) { AppRenderTargets targets; + vkcv::ImageConfig depthBufferConfig (width, height); targets.depthBuffer = core.createImage( AppConfig::depthBufferFormat, - width, - height, - 1, - false + depthBufferConfig ); + + vkcv::ImageConfig bufferConfig (width, height); + bufferConfig.setSupportingColorAttachment(true); targets.colorBuffer = core.createImage( AppConfig::colorBufferFormat, - width, - height, - 1, - false, - false, - true + bufferConfig ); targets.motionBuffer = core.createImage( AppConfig::motionBufferFormat, - width, - height, - 1, - false, - false, - true + bufferConfig ); return targets; diff --git a/projects/indirect_dispatch/src/MotionBlurSetup.cpp b/projects/indirect_dispatch/src/MotionBlurSetup.cpp index 0244c4ae9519ea6c6f818e024930e70c15e7a289..7589f77b80398e0bc1d7f1aec9b9570cc20acf3f 100644 --- a/projects/indirect_dispatch/src/MotionBlurSetup.cpp +++ b/projects/indirect_dispatch/src/MotionBlurSetup.cpp @@ -9,51 +9,37 @@ MotionBlurRenderTargets createRenderTargets(const uint32_t width, const uint32_t // divide and ceil to int const uint32_t motionMaxWidth = (width + (MotionBlurConfig::maxMotionTileSize - 1)) / MotionBlurConfig::maxMotionTileSize; - const uint32_t motionMaxheight = (height + (MotionBlurConfig::maxMotionTileSize - 1)) / MotionBlurConfig::maxMotionTileSize; + const uint32_t motionMaxHeight = (height + (MotionBlurConfig::maxMotionTileSize - 1)) / MotionBlurConfig::maxMotionTileSize; + vkcv::ImageConfig targetConfig (motionMaxWidth, motionMaxHeight); + targetConfig.setSupportingStorage(true); + targets.motionMax = core.createImage( MotionBlurConfig::motionVectorTileFormat, - motionMaxWidth, - motionMaxheight, - 1, - false, - true + targetConfig ); targets.motionMaxNeighbourhood = core.createImage( MotionBlurConfig::motionVectorTileFormat, - motionMaxWidth, - motionMaxheight, - 1, - false, - true + targetConfig ); targets.motionMin = core.createImage( MotionBlurConfig::motionVectorTileFormat, - motionMaxWidth, - motionMaxheight, - 1, - false, - true + targetConfig ); targets.motionMinNeighbourhood = core.createImage( MotionBlurConfig::motionVectorTileFormat, - motionMaxWidth, - motionMaxheight, - 1, - false, - true + targetConfig ); + + vkcv::ImageConfig outputConfig (width, height); + outputConfig.setSupportingStorage(true); targets.outputColor = core.createImage( MotionBlurConfig::outputColorFormat, - width, - height, - 1, - false, - true + outputConfig ); return targets; diff --git a/projects/indirect_draw/src/main.cpp b/projects/indirect_draw/src/main.cpp index 5951c8c0653011810902a6e8499d02c96d07fd1c..f90fa0892982f68fa959671b5eb6f207aac72b65 100644 --- a/projects/indirect_draw/src/main.cpp +++ b/projects/indirect_draw/src/main.cpp @@ -528,7 +528,13 @@ int main(int argc, const char** argv) { if ((!depthBuffer) || (swapchainWidth != core.getImageWidth(depthBuffer)) || (swapchainHeight != core.getImageHeight(depthBuffer))) { - depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight); + depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) + ); } cameraManager.update(dt); diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp index 512e1e6d1e6ea694289cb862ecae425b6bf8ee66..ceaeb43c891a09a7e730724bd22cdbea1b0b3f00 100644 --- a/projects/mesh_shader/src/main.cpp +++ b/projects/mesh_shader/src/main.cpp @@ -324,8 +324,10 @@ int main(int argc, const char** argv) { (swapchainHeight != core.getImageHeight(depthBuffer))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); } diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp index 00bb497b9798064c4b5ac449d6bac8495a1783e8..7f9e9fb7e12dd9c5e2437f2367d0f95eea67a0de 100644 --- a/projects/particle_simulation/src/main.cpp +++ b/projects/particle_simulation/src/main.cpp @@ -208,11 +208,17 @@ int main(int argc, const char **argv) { const auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); + vkcv::ImageConfig colorBufferConfig ( + swapchainExtent.width, + swapchainExtent.height + ); + + colorBufferConfig.setSupportingStorage(true); + colorBufferConfig.setSupportingColorAttachment(true); + vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true + colorBufferConfig ); vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); @@ -237,11 +243,12 @@ int main(int argc, const char **argv) { uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((core.getImageWidth(colorBuffer) != swapchainWidth) || (core.getImageHeight(colorBuffer) != swapchainHeight)) { + colorBufferConfig.setWidth(swapchainWidth); + colorBufferConfig.setHeight(swapchainHeight); + colorBuffer = core.createImage( colorFormat, - swapchainWidth, - swapchainHeight, - 1, false, true, true + colorBufferConfig ); } diff --git a/projects/path_tracer/src/main.cpp b/projects/path_tracer/src/main.cpp index 53f52c3d724b8db14641108d9b8a0e33e1844600..75ee36b2ac232e20d7baf29db34909dee67cca00 100644 --- a/projects/path_tracer/src/main.cpp +++ b/projects/path_tracer/src/main.cpp @@ -63,24 +63,23 @@ int main(int argc, const char** argv) { initialHeight, true ); + + vkcv::ImageConfig imageConfig ( + initialWidth, + initialHeight + ); + + imageConfig.setSupportingStorage(true); // images vkcv::ImageHandle outputImage = core.createImage( vk::Format::eR32G32B32A32Sfloat, - initialWidth, - initialHeight, - 1, - false, - true + imageConfig ); vkcv::ImageHandle meanImage = core.createImage( vk::Format::eR32G32B32A32Sfloat, - initialWidth, - initialHeight, - 1, - false, - true + imageConfig ); vkcv::shader::GLSLCompiler compiler; @@ -248,25 +247,19 @@ int main(int argc, const char** argv) { core.run([&](const vkcv::WindowHandle &windowHandle, double t, double dt, uint32_t swapchainWidth, uint32_t swapchainHeight) { - if (swapchainWidth != widthPrevious || swapchainHeight != heightPrevious) { + if ((swapchainWidth != widthPrevious) || (swapchainHeight != heightPrevious)) { + imageConfig.setWidth(swapchainWidth); + imageConfig.setHeight(swapchainHeight); // resize images outputImage = core.createImage( vk::Format::eR32G32B32A32Sfloat, - swapchainWidth, - swapchainHeight, - 1, - false, - true + imageConfig ); meanImage = core.createImage( vk::Format::eR32G32B32A32Sfloat, - swapchainWidth, - swapchainHeight, - 1, - false, - true + imageConfig ); // update descriptor sets diff --git a/projects/rtx_ambient_occlusion/src/main.cpp b/projects/rtx_ambient_occlusion/src/main.cpp index f5d8a46feefd070967d0f68742ad0c3b2749f160..2e999baee212aa6d9da8ca03d2649bafe69eccb8 100644 --- a/projects/rtx_ambient_occlusion/src/main.cpp +++ b/projects/rtx_ambient_occlusion/src/main.cpp @@ -101,8 +101,10 @@ int main(int argc, const char** argv) { ((swapchainHeight != core.getImageHeight(depthBuffer)))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); } diff --git a/projects/sph/src/main.cpp b/projects/sph/src/main.cpp index 043d135257ce63398ec34e5f6d47e4f4ffd6c61d..72cc9995dffd4ef8c938820f2678fac29c54e5ee 100644 --- a/projects/sph/src/main.cpp +++ b/projects/sph/src/main.cpp @@ -222,11 +222,17 @@ int main(int argc, const char **argv) { const auto swapchainExtent = core.getSwapchainExtent(window.getSwapchain()); + vkcv::ImageConfig colorBufferConfig ( + swapchainExtent.width, + swapchainExtent.height + ); + + colorBufferConfig.setSupportingStorage(true); + colorBufferConfig.setSupportingColorAttachment(true); + vkcv::ImageHandle colorBuffer = core.createImage( colorFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true + colorBufferConfig ); vkcv::effects::BloomAndFlaresEffect bloomAndFlares (core); @@ -245,11 +251,12 @@ int main(int argc, const char **argv) { uint32_t swapchainWidth, uint32_t swapchainHeight) { if ((core.getImageWidth(colorBuffer) != swapchainWidth) || (core.getImageHeight(colorBuffer) != swapchainHeight)) { + colorBufferConfig.setWidth(swapchainWidth); + colorBufferConfig.setHeight(swapchainHeight); + colorBuffer = core.createImage( colorFormat, - swapchainWidth, - swapchainHeight, - 1, false, true, true + colorBufferConfig ); } diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index ac2b2b6a19c23e039178da43705a4f1033fa6682..fecdaf98b8429dcb18c8aec811ce40c24eb5d0f4 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -387,48 +387,69 @@ int main(int argc, const char** argv) { skyPipeConfig.setWritingDepth(false); vkcv::GraphicsPipelineHandle skyPipe = core.createGraphicsPipeline(skyPipeConfig); + + vkcv::ImageConfig depthBufferConfig ( + swapchainExtent.width, + swapchainExtent.height + ); + + depthBufferConfig.setMultisampling(msaa); // render targets vkcv::ImageHandle depthBuffer = core.createImage( depthBufferFormat, + depthBufferConfig + ); + + const bool colorBufferRequiresStorage = !usingMsaa; + + vkcv::ImageConfig colorBufferConfig ( swapchainExtent.width, - swapchainExtent.height, - 1, false, false, false, msaa + swapchainExtent.height ); + + colorBufferConfig.setSupportingStorage(colorBufferRequiresStorage); + colorBufferConfig.setSupportingColorAttachment(true); + colorBufferConfig.setMultisampling(msaa); - const bool colorBufferRequiresStorage = !usingMsaa; vkcv::ImageHandle colorBuffer = core.createImage( colorBufferFormat, + colorBufferConfig + ); + + vkcv::ImageConfig resolveBufferConfig ( swapchainExtent.width, - swapchainExtent.height, - 1, false, colorBufferRequiresStorage, true, msaa + swapchainExtent.height ); + + resolveBufferConfig.setSupportingStorage(true); + resolveBufferConfig.setSupportingColorAttachment(true); vkcv::ImageHandle resolvedColorBuffer; if (usingMsaa) { resolvedColorBuffer = core.createImage( colorBufferFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true, true + resolveBufferConfig ); - } - else { + } else { resolvedColorBuffer = colorBuffer; } + vkcv::ImageConfig swapBufferConfig ( + swapchainExtent.width, + swapchainExtent.height + ); + + swapBufferConfig.setSupportingStorage(true); + vkcv::ImageHandle swapBuffer = core.createImage( colorBufferFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true + swapBufferConfig ); vkcv::ImageHandle swapBuffer2 = core.createImage( colorBufferFormat, - swapchainExtent.width, - swapchainExtent.height, - 1, false, true + swapBufferConfig ); const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); @@ -656,40 +677,48 @@ int main(int argc, const char** argv) { core.writeDescriptorSet(materialDescriptorSets[i], setWrites); } + depthBufferConfig.setWidth(fsrWidth); + depthBufferConfig.setHeight(fsrHeight); + depthBuffer = core.createImage( depthBufferFormat, - fsrWidth, fsrHeight, 1, - false, false, false, - msaa + depthBufferConfig ); + colorBufferConfig.setWidth(fsrWidth); + colorBufferConfig.setHeight(fsrHeight); + colorBuffer = core.createImage( colorBufferFormat, - fsrWidth, fsrHeight, 1, - false, colorBufferRequiresStorage, true, - msaa + colorBufferConfig ); if (usingMsaa) { + resolveBufferConfig.setWidth(fsrWidth); + resolveBufferConfig.setHeight(fsrHeight); + resolvedColorBuffer = core.createImage( colorBufferFormat, - fsrWidth, fsrHeight, 1, - false, true, true + resolveBufferConfig ); } else { resolvedColorBuffer = colorBuffer; } + swapBufferConfig.setWidth(fsrWidth); + swapBufferConfig.setHeight(fsrHeight); + swapBuffer = core.createImage( colorBufferFormat, - fsrWidth, fsrHeight, 1, - false, true + swapBufferConfig ); + swapBufferConfig.setWidth(swapchainWidth); + swapBufferConfig.setHeight(swapchainHeight); + swapBuffer2 = core.createImage( colorBufferFormat, - swapchainWidth, swapchainHeight, 1, - false, true + swapBufferConfig ); } @@ -955,8 +984,8 @@ int main(int argc, const char** argv) { upscaling2.setSharpness(sharpness); if (ImGui::Button("Reload forward pass")) { - vkcv::ShaderProgram newForwardProgram; + compiler.compile(vkcv::ShaderStage::VERTEX, std::filesystem::path("assets/shaders/shader.vert"), [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { newForwardProgram.addShader(shaderStage, path); @@ -973,8 +1002,8 @@ int main(int argc, const char** argv) { forwardPipeline = newPipeline; } } + if (ImGui::Button("Reload tonemapping")) { - vkcv::ShaderProgram newProgram; compiler.compile(vkcv::ShaderStage::COMPUTE, std::filesystem::path("assets/shaders/tonemapping.comp"), [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) { @@ -990,6 +1019,7 @@ int main(int argc, const char** argv) { tonemappingPipeline = newPipeline; } } + ImGui::End(); } diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp index 1c3eb776b43d29ffe53aa62a03e3bc06fe145767..9a5548b7189030e3a3296edb0486cef5c9225dd1 100644 --- a/projects/wobble_bobble/src/main.cpp +++ b/projects/wobble_bobble/src/main.cpp @@ -309,8 +309,10 @@ int main(int argc, const char **argv) { vkcv::ImageHandle depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainExtent.width, - swapchainExtent.height + vkcv::ImageConfig( + swapchainExtent.width, + swapchainExtent.height + ) ); vkcv::Image grid = vkcv::image( @@ -605,8 +607,10 @@ int main(int argc, const char **argv) { if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { depthBuffer = core.createImage( vk::Format::eD32Sfloat, - swapchainWidth, - swapchainHeight + vkcv::ImageConfig( + swapchainWidth, + swapchainHeight + ) ); swapchainExtent.width = swapchainWidth; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 6ccf1de841996c85905689f0ef45e3dbdcf7c285..99a516ad96e6feaf90990f1be8747ff967ada9ab 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -859,17 +859,24 @@ namespace vkcv { mipLodBias, borderColor); } - ImageHandle Core::createImage(vk::Format format, uint32_t width, uint32_t height, - uint32_t depth, bool createMipChain, bool supportStorage, - bool supportColorAttachment, Multisampling multisampling) { + ImageHandle Core::createImage(vk::Format format, + const ImageConfig& config, + bool createMipChain) { uint32_t mipCount = 1; if (createMipChain) { - mipCount = - 1 + (uint32_t)std::floor(std::log2(std::max(width, std::max(height, depth)))); + mipCount = 1 + (uint32_t) std::floor( + std::log2(std::max( + config.getWidth(), + std::max(config.getHeight(), config.getDepth())) + ) + ); } - return m_ImageManager->createImage(width, height, depth, format, mipCount, supportStorage, - supportColorAttachment, multisampling); + return m_ImageManager->createImage( + format, + mipCount, + config + ); } void Core::fillImage(const ImageHandle &image, const void* data, size_t size) { diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp index 6e5b5fc1b3efbbcf4203e9825230eca20cbf55e5..63a395e7f8f0e590d6b2dbdde3f8d527c4d8c87b 100644 --- a/src/vkcv/Image.cpp +++ b/src/vkcv/Image.cpp @@ -75,9 +75,22 @@ namespace vkcv { Image image(Core &core, vk::Format format, uint32_t width, uint32_t height, uint32_t depth, bool createMipChain, bool supportStorage, bool supportColorAttachment, Multisampling multisampling) { - return Image(&core, - core.createImage(format, width, height, depth, createMipChain, supportStorage, - supportColorAttachment, multisampling)); + ImageConfig config (width, height, depth); + config.setSupportingStorage(supportStorage); + config.setSupportingColorAttachment(supportColorAttachment); + config.setMultisampling(multisampling); + return image(core, format, config, createMipChain); + } + + Image image(Core &core, vk::Format format, const ImageConfig &config, bool createMipChain) { + return Image( + &core, + core.createImage( + format, + config, + createMipChain + ) + ); } } // namespace vkcv diff --git a/src/vkcv/ImageConfig.cpp b/src/vkcv/ImageConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d95a7ff6bb843b4405f119d6bec0e50a06658e0e --- /dev/null +++ b/src/vkcv/ImageConfig.cpp @@ -0,0 +1,80 @@ +/** + * @authors Tobias Frisch + * @file vkcv/Image.cpp + * @brief Structure for image configuration + */ +#include "vkcv/ImageConfig.hpp" + +namespace vkcv { + + ImageConfig::ImageConfig(uint32_t width, + uint32_t height, + uint32_t depth) + : m_width(width), + m_height(height), + m_depth(depth), + + m_supportStorage(false), + m_supportColorAttachment(false), + m_cubeMapImage(false), + + m_msaa(Multisampling::None) + {} + + uint32_t ImageConfig::getWidth() const { + return m_width; + } + + void ImageConfig::setWidth(uint32_t width) { + m_width = width; + } + + uint32_t ImageConfig::getHeight() const { + return m_height; + } + + void ImageConfig::setHeight(uint32_t height) { + m_height = height; + } + + uint32_t ImageConfig::getDepth() const { + return m_depth; + } + + void ImageConfig::setDepth(uint32_t depth) { + m_depth = depth; + } + + bool ImageConfig::isSupportingStorage() const { + return m_supportStorage; + } + + void ImageConfig::setSupportingStorage(bool supportStorage) { + m_supportStorage = supportStorage; + } + + bool ImageConfig::isSupportingColorAttachment() const { + return m_supportColorAttachment; + } + + void ImageConfig::setSupportingColorAttachment(bool supportColorAttachment) { + m_supportColorAttachment = supportColorAttachment; + } + + bool ImageConfig::isCubeMapImage() const { + return m_cubeMapImage; + } + + void ImageConfig::setCubeMapImage(bool cubeMapImage) { + m_cubeMapImage = cubeMapImage; + } + + Multisampling ImageConfig::getMultisampling() const { + return m_msaa; + } + + void ImageConfig::setMultisampling(Multisampling msaa) { + m_msaa = msaa; + } + +} \ No newline at end of file diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 993243cb5644dd3a1527f3c50efadc9fdc9aa299..56e2bc91e404c6205e44a69affce081a994fee0e 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -153,21 +153,22 @@ namespace vkcv { } } - ImageHandle ImageManager::createImage(uint32_t width, uint32_t height, uint32_t depth, - vk::Format format, uint32_t mipCount, bool supportStorage, - bool supportColorAttachment, Multisampling msaa) { + ImageHandle ImageManager::createImage(vk::Format format, + uint32_t mipCount, + const ImageConfig& config) { const vk::PhysicalDevice &physicalDevice = getCore().getContext().getPhysicalDevice(); - const vk::FormatProperties formatProperties = physicalDevice.getFormatProperties(format); vk::ImageCreateFlags createFlags; - vk::ImageUsageFlags imageUsageFlags = - (vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst - | vk::ImageUsageFlagBits::eTransferSrc); + vk::ImageUsageFlags imageUsageFlags = ( + vk::ImageUsageFlagBits::eSampled | + vk::ImageUsageFlagBits::eTransferDst | + vk::ImageUsageFlagBits::eTransferSrc + ); vk::ImageTiling imageTiling = vk::ImageTiling::eOptimal; - if (supportStorage) { + if (config.isSupportingStorage()) { imageUsageFlags |= vk::ImageUsageFlagBits::eStorage; if (!(formatProperties.optimalTilingFeatures @@ -180,7 +181,7 @@ namespace vkcv { } } - if (supportColorAttachment) { + if (config.isSupportingColorAttachment()) { imageUsageFlags |= vk::ImageUsageFlagBits::eColorAttachment; } @@ -195,8 +196,8 @@ namespace vkcv { vk::ImageType imageType = vk::ImageType::e3D; vk::ImageViewType imageViewType = vk::ImageViewType::e3D; - if (depth <= 1) { - if (height <= 1) { + if (config.getDepth() <= 1) { + if (config.getHeight() <= 1) { imageType = vk::ImageType::e1D; imageViewType = vk::ImageViewType::e1D; } else { @@ -209,7 +210,11 @@ namespace vkcv { imageType = vk::ImageType::e2D; imageViewType = vk::ImageViewType::e2D; } - + + if (config.isCubeMapImage()) { + imageViewType = vk::ImageViewType::eCube; + createFlags |= vk::ImageCreateFlagBits::eCubeCompatible; + } else if (vk::ImageType::e3D == imageType) { createFlags |= vk::ImageCreateFlagBits::e2DArrayCompatible; } @@ -221,27 +226,53 @@ namespace vkcv { imageTiling = vk::ImageTiling::eLinear; } - const vk::ImageFormatProperties imageFormatProperties = - physicalDevice.getImageFormatProperties(format, imageType, imageTiling, - imageUsageFlags); + const vk::ImageFormatProperties imageFormatProperties = ( + physicalDevice.getImageFormatProperties( + format, + imageType, + imageTiling, + imageUsageFlags + ) + ); const uint32_t arrayLayers = std::min<uint32_t>(1, imageFormatProperties.maxArrayLayers); const vk::ImageCreateInfo imageCreateInfo( - createFlags, imageType, format, vk::Extent3D(width, height, depth), mipCount, - arrayLayers, msaaToSampleCountFlagBits(msaa), imageTiling, imageUsageFlags, - vk::SharingMode::eExclusive, {}, vk::ImageLayout::eUndefined); + createFlags, + imageType, + format, + vk::Extent3D( + config.getWidth(), + config.getHeight(), + config.getDepth() + ), + mipCount, + arrayLayers, + msaaToSampleCountFlagBits( + config.getMultisampling() + ), + imageTiling, + imageUsageFlags, + vk::SharingMode::eExclusive, + {}, + vk::ImageLayout::eUndefined + ); auto imageAllocation = allocator.createImage( imageCreateInfo, - vma::AllocationCreateInfo(vma::AllocationCreateFlags(), vma::MemoryUsage::eGpuOnly, - vk::MemoryPropertyFlagBits::eDeviceLocal, - vk::MemoryPropertyFlagBits::eDeviceLocal, 0, vma::Pool(), - nullptr)); + vma::AllocationCreateInfo( + vma::AllocationCreateFlags(), + vma::MemoryUsage::eGpuOnly, + vk::MemoryPropertyFlagBits::eDeviceLocal, + vk::MemoryPropertyFlagBits::eDeviceLocal, + 0, + vma::Pool(), + nullptr + ) + ); vk::Image image = imageAllocation.first; vma::Allocation allocation = imageAllocation.second; - vk::ImageAspectFlags aspectFlags; if (isDepthFormat) { @@ -257,37 +288,65 @@ namespace vkcv { for (uint32_t mip = 0; mip < mipCount; mip++) { const vk::ImageViewCreateInfo imageViewCreateInfo( - {}, image, imageViewType, format, + {}, + image, + imageViewType, + format, vk::ComponentMapping( - vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, - vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity), - vk::ImageSubresourceRange(aspectFlags, mip, mipCount - mip, 0, arrayLayers)); + vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity + ), + vk::ImageSubresourceRange( + aspectFlags, + mip, + mipCount - mip, + 0, + arrayLayers + ) + ); views.push_back(device.createImageView(imageViewCreateInfo)); } for (uint32_t mip = 0; mip < mipCount; mip++) { const vk::ImageViewCreateInfo imageViewCreateInfo( - {}, image, vk::ImageViewType::e2DArray, format, + {}, + image, + vk::ImageViewType::e2DArray, + format, vk::ComponentMapping( - vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity, - vk::ComponentSwizzle::eIdentity, vk::ComponentSwizzle::eIdentity), - vk::ImageSubresourceRange(aspectFlags, mip, 1, 0, arrayLayers)); + vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity, + vk::ComponentSwizzle::eIdentity + ), + vk::ImageSubresourceRange( + aspectFlags, + mip, + 1, + 0, + arrayLayers + ) + ); arrayViews.push_back(device.createImageView(imageViewCreateInfo)); } - return add({ image, allocation, - - views, arrayViews, - - width, height, depth, - - format, arrayLayers, vk::ImageLayout::eUndefined, supportStorage }); - } - - ImageHandle ImageManager::createSwapchainImage() const { - return ImageHandle::createSwapchainImageHandle(); + return add({ + image, + allocation, + views, + arrayViews, + config.getWidth(), + config.getHeight(), + config.getDepth(), + format, + arrayLayers, + vk::ImageLayout::eUndefined, + config.isSupportingStorage() + }); } vk::Image ImageManager::getVulkanImage(const ImageHandle &handle) const { @@ -562,17 +621,19 @@ namespace vkcv { assert(images.size() == views.size()); m_swapchainImages.clear(); for (size_t i = 0; i < images.size(); i++) { - m_swapchainImages.push_back({ images [i], - nullptr, - { views [i] }, - {}, - width, - height, - 1, - format, - 1, - vk::ImageLayout::eUndefined, - false }); + m_swapchainImages.push_back({ + images [i], + nullptr, + { views [i] }, + {}, + width, + height, + 1, + format, + 1, + vk::ImageLayout::eUndefined, + false + }); } } diff --git a/src/vkcv/ImageManager.hpp b/src/vkcv/ImageManager.hpp index ddc44f9b519061a7881eb0904034da2276b82a12..5a91d962370071ac9c557ad877fd26268e1e2b2a 100644 --- a/src/vkcv/ImageManager.hpp +++ b/src/vkcv/ImageManager.hpp @@ -10,7 +10,7 @@ #include "BufferManager.hpp" #include "HandleManager.hpp" -#include "vkcv/Multisampling.hpp" +#include "vkcv/ImageConfig.hpp" namespace vkcv { @@ -86,12 +86,9 @@ namespace vkcv { ~ImageManager() noexcept override; - [[nodiscard]] ImageHandle createImage(uint32_t width, uint32_t height, uint32_t depth, - vk::Format format, uint32_t mipCount, - bool supportStorage, bool supportColorAttachment, - Multisampling msaa); - - [[nodiscard]] ImageHandle createSwapchainImage() const; + [[nodiscard]] ImageHandle createImage(vk::Format format, + uint32_t mipCount, + const ImageConfig& config); [[nodiscard]] vk::Image getVulkanImage(const ImageHandle &handle) const;