From ae9ff0ae285691d038c88c8ad4a5a86ff93daa9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 7 Mar 2021 22:10:14 +0100 Subject: [PATCH] Vk: implement a Sampler wrapper. Together with SamplerFilter, SamplerMipmap and SamplerWrapping enums convertible from the generic versions, which finally deprecate the last remaining vk*() conversion functions in Enums.h and thus the whole header as well. The EnumsTest executable is also no more, as the rest of it now resides inside SamplerTest. --- doc/snippets/MagnumVk.cpp | 25 +++ doc/vulkan-mapping.dox | 14 +- src/Magnum/Sampler.h | 52 +++-- src/Magnum/Vk/CMakeLists.txt | 10 +- src/Magnum/Vk/Enums.cpp | 58 +---- src/Magnum/Vk/Enums.h | 79 ++++--- src/Magnum/Vk/Sampler.cpp | 242 +++++++++++++++++++++ src/Magnum/Vk/Sampler.h | 145 +++++++++++++ src/Magnum/Vk/SamplerCreateInfo.h | 308 +++++++++++++++++++++++++++ src/Magnum/Vk/Test/CMakeLists.txt | 9 +- src/Magnum/Vk/Test/EnumsTest.cpp | 153 ------------- src/Magnum/Vk/Test/SamplerTest.cpp | 289 +++++++++++++++++++++++++ src/Magnum/Vk/Test/SamplerVkTest.cpp | 100 +++++++++ src/Magnum/Vk/Vk.h | 5 + 14 files changed, 1206 insertions(+), 283 deletions(-) create mode 100644 src/Magnum/Vk/Sampler.cpp create mode 100644 src/Magnum/Vk/Sampler.h create mode 100644 src/Magnum/Vk/SamplerCreateInfo.h delete mode 100644 src/Magnum/Vk/Test/EnumsTest.cpp create mode 100644 src/Magnum/Vk/Test/SamplerTest.cpp create mode 100644 src/Magnum/Vk/Test/SamplerVkTest.cpp diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index 9c419c424..06277b312 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -31,6 +31,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Mesh.h" #include "Magnum/PixelFormat.h" +#include "Magnum/Sampler.h" #include "Magnum/VertexFormat.h" #include "Magnum/Math/Color.h" #include "Magnum/Vk/Assert.h" @@ -59,6 +60,7 @@ #include "Magnum/Vk/RasterizationPipelineCreateInfo.h" #include "Magnum/Vk/RenderPassCreateInfo.h" #include "Magnum/Vk/Result.h" +#include "Magnum/Vk/SamplerCreateInfo.h" #include "Magnum/Vk/ShaderCreateInfo.h" #include "Magnum/Vk/ShaderSet.h" #include "MagnumExternal/Vulkan/flextVkGlobal.h" @@ -1031,6 +1033,29 @@ cmd.begin() /* [RenderPass-usage-end] */ } +{ +Vk::Device device{NoCreate}; +/* The include should be a no-op here since it was already included above */ +/* [Sampler-creation] */ +#include + +DOXYGEN_IGNORE() + +Vk::Sampler sampler{device, Vk::SamplerCreateInfo{}}; +/* [Sampler-creation] */ +} + +{ +Vk::Device device{NoCreate}; +/* [Sampler-creation-linear] */ +Vk::Sampler sampler{device, Vk::SamplerCreateInfo{} + .setMinificationFilter(SamplerFilter::Linear, SamplerMipmap::Linear) + .setMagnificationFilter(SamplerFilter::Linear) + .setWrapping(SamplerWrapping::ClampToEdge) +}; +/* [Sampler-creation-linear] */ +} + { Vk::Device device{NoCreate}; /* The include should be a no-op here since it was already included above */ diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index f0000896e..1ab6265c7 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -77,7 +77,7 @@ Vulkan handle | Matching API @type_vk{QueryPool} | | @type_vk{Queue} | @ref Queue @type_vk{RenderPass} | @ref RenderPass -@type_vk{Sampler} | | +@type_vk{Sampler} | @ref Sampler @type_vk{SamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{Semaphore} | | @type_vk{ShaderModule} | @ref Shader @@ -205,7 +205,7 @@ Vulkan function | Matching API @fn_vk{CreatePipelineLayout}, \n @fn_vk{DestroyPipelineLayout} | @ref PipelineLayout constructor and destructor @fn_vk{CreateQueryPool}, \n @fn_vk{DestroyQueryPool} | | @fn_vk{CreateRenderPass}, \n @fn_vk{CreateRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{DestroyRenderPass} | @ref RenderPass constructor and destructor -@fn_vk{CreateSampler}, \n @fn_vk{DestroySampler} | | +@fn_vk{CreateSampler}, \n @fn_vk{DestroySampler} | @ref Sampler constructor and destructor @fn_vk{CreateSamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** , \n @fn_vk{DestroySamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @fn_vk{CreateSemaphore}, \n @fn_vk{DestroySemaphore} | | @fn_vk{CreateShaderModule}, \n @fn_vk{DestroyShaderModule} | @ref Shader constructor and destructor @@ -707,7 +707,7 @@ Vulkan structure | Matching API Vulkan structure | Matching API --------------------------------------- | ------------ -@type_vk{SamplerCreateInfo} | | +@type_vk{SamplerCreateInfo} | @ref SamplerCreateInfo @type_vk{SamplerReductionModeCreateInfo} @m_class{m-label m-flat m-success} **EXT, 1.2** | | @type_vk{SamplerYcbcrConversionCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{SamplerYcbcrConversionImageFormatProperties} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @@ -854,7 +854,7 @@ Vulkan enum | Matching API Vulkan enum | Matching API --------------------------------------- | ------------ -@type_vk{Filter} | only @ref vkFilter() +@type_vk{Filter} | @ref SamplerFilter @type_vk{Format} | @ref PixelFormat, @ref VertexFormat @type_vk{FormatFeatureFlagBits}, \n @type_vk{FormatFeatureFlags} | | @type_vk{FramebufferCreateFlagBits}, \n @type_vk{FramebufferCreateFlags} | @ref FramebufferCreateInfo::Flag, \n @ref FramebufferCreateInfo::Flags @@ -960,9 +960,9 @@ Vulkan enum | Matching API Vulkan enum | Matching API --------------------------------------- | ------------ @type_vk{SampleCountFlagBits}, \n @type_vk{SampleCountFlags} | not exposed, using plain integers instead -@type_vk{SamplerAddressMode} | only @ref vkSamplerAddressMode() -@type_vk{SamplerMipmapMode} | only @ref vkSamplerMipmapMode() -@type_vk{SamplerCreateFlagBits}, \n @type_vk{SamplerCreateFlags} | | +@type_vk{SamplerAddressMode} | @ref SamplerWrapping +@type_vk{SamplerMipmapMode} | @ref SamplerMipmap +@type_vk{SamplerCreateFlagBits}, \n @type_vk{SamplerCreateFlags} | @ref SamplerCreateInfo::Flag, \n @ref SamplerCreateInfo::Flags @type_vk{SamplerReductionMode} @m_class{m-label m-flat m-success} **EXT, 1.2** | | @type_vk{SamplerYcbcrModelConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{SamplerYcbcrRange} @m_class{m-label m-flat m-success} **KHR, 1.1** | | diff --git a/src/Magnum/Sampler.h b/src/Magnum/Sampler.h index 97eca31cd..dd4886399 100644 --- a/src/Magnum/Sampler.h +++ b/src/Magnum/Sampler.h @@ -41,8 +41,8 @@ In case of OpenGL, corresponds to @ref GL::SamplerFilter and is convertible to it using @ref GL::samplerFilter(). See documentation of each value for more information about the mapping. -In case of Vulkan, corresponds to @type_vk_keyword{Filter} and is convertible -to it using @ref Vk::vkFilter(). See documentation of each value for more +In case of Vulkan, corresponds to @ref Vk::SamplerFilter and is convertible to +it using @ref Vk::samplerFilter(). See documentation of each value for more information about the mapping. @see @ref SamplerMipmap, @ref SamplerWrapping */ @@ -55,7 +55,7 @@ enum class SamplerFilter: UnsignedInt { * Nearest neighbor filtering. * * Corresponds to @ref GL::SamplerFilter::Nearest / - * @val_vk_keyword{FILTER_NEAREST,Filter}. + * @ref Vk::SamplerFilter::Nearest. */ Nearest = 0, @@ -63,7 +63,7 @@ enum class SamplerFilter: UnsignedInt { * Linear interpolation filtering. * * Corresponds to @ref GL::SamplerFilter::Linear / - * @val_vk_keyword{FILTER_LINEAR,Filter}. + * @ref Vk::SamplerFilter::Linear. */ Linear }; @@ -75,9 +75,9 @@ In case of OpenGL, corresponds to @ref GL::SamplerMipmap and is convertible to it using @ref GL::samplerMipmap(). See documentation of each value for more information about the mapping. -In case of Vulkan, corresponds to @type_vk_keyword{SamplerMipmapMode} and is -convertible to it using @ref Vk::vkSamplerMipmapMode(). See documentation of -each value for more information about the mapping. +In case of Vulkan, corresponds to @ref Vk::SamplerMipmap and is convertible to +it using @ref Vk::samplerMipmap(). See documentation of each value for more +information about the mapping. @see @ref SamplerFilter, @ref SamplerWrapping */ enum class SamplerMipmap: UnsignedInt { @@ -89,9 +89,8 @@ enum class SamplerMipmap: UnsignedInt { * Select base mip level * * Corresponds to @ref GL::SamplerMipmap::Base. On Vulkan, the - * corresponding mode is - * @val_vk_keyword{SAMPLER_MIPMAP_MODE_NEAREST,SamplerMipmapMode} and you - * have to configure the sampler to use just a single mipmap level. + * corresponding mode is @ref Vk::SamplerMipmap::Nearest and you have to + * configure the sampler to use just a single mipmap level. */ Base = 0, @@ -99,7 +98,7 @@ enum class SamplerMipmap: UnsignedInt { * Select nearest mip level. * * Corresponds to @ref GL::SamplerMipmap::Nearest / - * @val_vk_keyword{SAMPLER_MIPMAP_MODE_NEAREST,SamplerMipmapMode}. + * @ref Vk::SamplerMipmap::Nearest. */ Nearest, @@ -107,7 +106,7 @@ enum class SamplerMipmap: UnsignedInt { * Linear interpolation of nearest mip levels. * * Corresponds to @ref GL::SamplerMipmap::Linear / - * @val_vk_keyword{SAMPLER_MIPMAP_MODE_LINEAR,SamplerMipmapMode}. + * @ref Vk::SamplerMipmap::Linear. */ Linear }; @@ -120,10 +119,9 @@ to it using @ref GL::samplerWrapping(). See documentation of each value for more information about the mapping. Note that not every mode is available on all targets, use @ref GL::hasSamplerWrapping() to check for its presence. -In case of Vulkan, corresponds to @type_vk_keyword{SamplerAddressMode} and is -convertible to it using @ref Vk::vkSamplerAddressMode(). See documentation of -each value for more information about the mapping. Note that not every mode is available there, use @ref Vk::hasVkSamplerAddressMode() to check for its -presence. +In case of Vulkan, corresponds to @ref Vk::SamplerWrapping and is convertible +to it using @ref Vk::samplerWrapping(). See documentation of each value for +more information about the mapping. @see @ref SamplerFilter, @ref SamplerMipmap */ enum class SamplerWrapping: UnsignedInt { @@ -132,36 +130,36 @@ enum class SamplerWrapping: UnsignedInt { good default */ /** - * Repeat texture. + * Repeat the texture. * * Corresponds to @ref GL::SamplerWrapping::Repeat / - * @val_vk_keyword{SAMPLER_ADDRESS_MODE_REPEAT,SamplerAddressMode}. + * @ref Vk::SamplerWrapping::Repeat. */ Repeat = 0, /** - * Repeat mirrored texture. + * Repeat a mirrored texture. * * Corresponds to @ref GL::SamplerWrapping::MirroredRepeat / - * @val_vk_keyword{SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,SamplerAddressMode}. + * @ref Vk::SamplerWrapping::MirroredRepeat. */ MirroredRepeat, /** - * Clamp to edge. Coordinates out of the range will be clamped to - * first / last column / row in given direction. + * Clamp to edge. Coordinates out of range will be clamped to the first / + * last column / row in given direction. * * Corresponds to @ref GL::SamplerWrapping::ClampToEdge / - * @val_vk_keyword{SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,SamplerAddressMode}. + * @ref Vk::SamplerWrapping::ClampToEdge. */ ClampToEdge, /** - * Clamp to border color. Coordinates out of range will be clamped - * to border color. + * Clamp to border color. Coordinates out of range will be clamped to + * the border color. * * Corresponds to @ref GL::SamplerWrapping::ClampToBorder / - * @val_vk_keyword{SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,SamplerAddressMode}. + * @ref Vk::SamplerWrapping::ClampToBorder. */ ClampToBorder, @@ -170,7 +168,7 @@ enum class SamplerWrapping: UnsignedInt { * edge after that. * * Corresponds to @ref GL::SamplerWrapping::MirrorClampToEdge. / - * @val_vk_keyword{SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,SamplerAddressMode}. + * @ref Vk::SamplerWrapping::MirrorClampToEdge. */ MirrorClampToEdge }; diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 5b6701875..7a2a08b57 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -49,7 +49,6 @@ set(MagnumVk_GracefulAssert_SRCS Device.cpp DeviceProperties.cpp DeviceFeatures.cpp - Enums.cpp ExtensionProperties.cpp Image.cpp ImageView.cpp @@ -61,6 +60,7 @@ set(MagnumVk_GracefulAssert_SRCS Pipeline.cpp PixelFormat.cpp RenderPass.cpp + Sampler.cpp ShaderSet.cpp VertexFormat.cpp) @@ -76,7 +76,6 @@ set(MagnumVk_HEADERS DeviceCreateInfo.h DeviceFeatures.h DeviceProperties.h - Enums.h Extensions.h ExtensionProperties.h Fence.h @@ -105,6 +104,8 @@ set(MagnumVk_HEADERS RenderPass.h RenderPassCreateInfo.h Result.h + Sampler.h + SamplerCreateInfo.h Shader.h ShaderCreateInfo.h ShaderSet.h @@ -130,6 +131,11 @@ set(MagnumVk_PRIVATE_HEADERS Implementation/structureHelpers.h Implementation/vertexFormatMapping.hpp) +if(MAGNUM_BUILD_DEPRECATED) + list(APPEND MagnumVk_SRCS Enums.cpp) + list(APPEND MagnumVk_HEADERS Enums.h) +endif() + # Objects shared between main and test library add_library(MagnumVkObjects OBJECT ${MagnumVk_SRCS} diff --git a/src/Magnum/Vk/Enums.cpp b/src/Magnum/Vk/Enums.cpp index 443873d07..b464ac01c 100644 --- a/src/Magnum/Vk/Enums.cpp +++ b/src/Magnum/Vk/Enums.cpp @@ -23,46 +23,18 @@ DEALINGS IN THE SOFTWARE. */ -#include "Enums.h" - -#include +#define _MAGNUM_NO_DEPRECATED_VK_ENUMS -#include "Magnum/Mesh.h" -#include "Magnum/Sampler.h" +#include "Enums.h" -#ifdef MAGNUM_BUILD_DEPRECATED #include "Magnum/Vk/MeshLayout.h" #include "Magnum/Vk/Mesh.h" #include "Magnum/Vk/PixelFormat.h" +#include "Magnum/Vk/SamplerCreateInfo.h" #include "Magnum/Vk/VertexFormat.h" -#endif namespace Magnum { namespace Vk { -namespace { - -constexpr VkFilter FilterMapping[]{ - VK_FILTER_NEAREST, - VK_FILTER_LINEAR -}; - -constexpr VkSamplerMipmapMode SamplerMipmapModeMapping[]{ - VK_SAMPLER_MIPMAP_MODE_NEAREST, /* See vkSamplerMipmapMode() for details */ - VK_SAMPLER_MIPMAP_MODE_NEAREST, - VK_SAMPLER_MIPMAP_MODE_LINEAR -}; - -constexpr VkSamplerAddressMode SamplerAddressModeMapping[]{ - VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, -}; - -} - -#ifdef MAGNUM_BUILD_DEPRECATED bool hasVkPrimitiveTopology(const Magnum::MeshPrimitive primitive) { return hasMeshPrimitive(primitive); } @@ -71,7 +43,7 @@ VkPrimitiveTopology vkPrimitiveTopology(const Magnum::MeshPrimitive primitive) { return VkPrimitiveTopology(meshPrimitive(primitive)); } -bool hasVkIndexType(const Magnum::MeshIndexType) { +bool hasVkIndexType(Magnum::MeshIndexType) { return true; } @@ -102,33 +74,21 @@ VkFormat vkFormat(const Magnum::PixelFormat format) { VkFormat vkFormat(const Magnum::CompressedPixelFormat format) { return VkFormat(pixelFormat(format)); } -#endif VkFilter vkFilter(const Magnum::SamplerFilter filter) { - CORRADE_ASSERT(UnsignedInt(filter) < Containers::arraySize(FilterMapping), - "Vk::vkFilter(): invalid filter" << filter, {}); - return FilterMapping[UnsignedInt(filter)]; + return VkFilter(samplerFilter(filter)); } VkSamplerMipmapMode vkSamplerMipmapMode(const Magnum::SamplerMipmap mipmap) { - CORRADE_ASSERT(UnsignedInt(mipmap) < Containers::arraySize(SamplerMipmapModeMapping), - "Vk::vkSamplerMipmapMode(): invalid mode" << mipmap, {}); - return SamplerMipmapModeMapping[UnsignedInt(mipmap)]; + return VkSamplerMipmapMode(samplerMipmap(mipmap)); } -bool hasVkSamplerAddressMode(const Magnum::SamplerWrapping wrapping) { - CORRADE_ASSERT(UnsignedInt(wrapping) < Containers::arraySize(SamplerAddressModeMapping), - "Vk::hasVkSamplerAddressMode(): invalid wrapping" << wrapping, {}); - return UnsignedInt(SamplerAddressModeMapping[UnsignedInt(wrapping)]) != ~UnsignedInt{}; +bool hasVkSamplerAddressMode(Magnum::SamplerWrapping) { + return true; } VkSamplerAddressMode vkSamplerAddressMode(const Magnum::SamplerWrapping wrapping) { - CORRADE_ASSERT(UnsignedInt(wrapping) < Containers::arraySize(SamplerAddressModeMapping), - "Vk::vkSamplerAddressMode(): invalid wrapping" << wrapping, {}); - const VkSamplerAddressMode out = SamplerAddressModeMapping[UnsignedInt(wrapping)]; - CORRADE_ASSERT(out != VkSamplerAddressMode(~UnsignedInt{}), - "Vk::vkSamplerAddressMode(): unsupported wrapping" << wrapping, {}); - return out; + return VkSamplerAddressMode(samplerWrapping(wrapping)); } }} diff --git a/src/Magnum/Vk/Enums.h b/src/Magnum/Vk/Enums.h index 838f4f084..ae2174b6f 100644 --- a/src/Magnum/Vk/Enums.h +++ b/src/Magnum/Vk/Enums.h @@ -25,27 +25,31 @@ DEALINGS IN THE SOFTWARE. */ +#ifdef MAGNUM_BUILD_DEPRECATED /** @file * @brief Function @ref Magnum::Vk::hasVkPrimitiveTopology(), @ref Magnum::Vk::vkPrimitiveTopology(), @ref Magnum::Vk::hasVkIndexType(), @ref Magnum::Vk::vkIndexType(), @ref Magnum::Vk::hasVkFormat(), @ref Magnum::Vk::vkFormat(), @ref Magnum::Vk::vkFilter(), @ref Magnum::Vk::vkSamplerMipmapMode(), @ref Magnum::Vk::hasVkSamplerAddressMode(), @ref Magnum::Vk::vkSamplerAddressMode() + * @m_deprecated_since_latest All functionality in this header has been + * deprecated and moved elsewhere. Use headers corresponding to the + * suggested replacement APIs instead. */ +#endif -#include "Magnum/Magnum.h" +#include "Magnum/configure.h" + +#ifdef MAGNUM_BUILD_DEPRECATED +#include "Magnum/Array.h" /* That's fine, we're deprecated too */ #include "Magnum/Math/Vector3.h" #include "Magnum/Vk/Vulkan.h" #include "Magnum/Vk/visibility.h" -#ifdef MAGNUM_BUILD_DEPRECATED #include -#endif -#ifdef MAGNUM_BUILD_DEPRECATED -/* For implicit conversions to Vector, not used otherwise */ -#include "Magnum/Array.h" +#ifndef _MAGNUM_NO_DEPRECATED_VK_ENUMS +CORRADE_DEPRECATED_FILE("use headers corresponding to the suggested replacement APIs instead") #endif namespace Magnum { namespace Vk { -#ifdef MAGNUM_BUILD_DEPRECATED /** * @brief @copybrief hasMeshPrimitive() * @m_deprecated_since_latest Use @ref hasMeshPrimitive() instead. @@ -109,51 +113,37 @@ CORRADE_DEPRECATED("use pixelFormat() instead") MAGNUM_VK_EXPORT VkFormat vkForm * instead. */ CORRADE_DEPRECATED("use pixelFormat() instead") MAGNUM_VK_EXPORT VkFormat vkFormat(Magnum::CompressedPixelFormat format); -#endif /** -@brief Convert generic sampler filter to Vulkan filter - -@see @ref vkSamplerMipmapMode(), @ref vkSamplerAddressMode() -*/ -MAGNUM_VK_EXPORT VkFilter vkFilter(Magnum::SamplerFilter filter); + * @brief @copybrief samplerFilter() + * @m_deprecated_since_latest Use @ref samplerFilter() instead. + */ +CORRADE_DEPRECATED("use samplerFilter() instead") MAGNUM_VK_EXPORT VkFilter vkFilter(Magnum::SamplerFilter filter); /** -@brief Convert generic sampler mipomap mode to Vulkan sampler mipmap mode - -Vulkan doesn't support the @ref SamplerMipmap::Base value directly, instead -@val_vk{SAMPLER_MIPMAP_MODE_NEAREST,SamplerMipmapMode} is used and you have to -configure the sampler to use just a single mipmap level. -@see @ref vkFilter(), @ref vkSamplerAddressMode() -*/ -MAGNUM_VK_EXPORT VkSamplerMipmapMode vkSamplerMipmapMode(Magnum::SamplerMipmap mipmap); + * @brief @copybrief samplerMipmap() + * @m_deprecated_since_latest Use @ref samplerMipmap() instead. + */ +CORRADE_DEPRECATED("use samplerMipmap() instead") MAGNUM_VK_EXPORT VkSamplerMipmapMode vkSamplerMipmapMode(Magnum::SamplerMipmap mipmap); /** -@brief Check availability of a generic sampler wrapping mode - -Returns @cpp false @ce if Vulkan doesn't support such wrapping, @cpp true @ce -otherwise. The @p wrapping value is expected to be valid. - -@note Support of some modes depends on presence of a particular Vulkan - extension. Such check is outside of the scope of this function and you are - expected to verify extension availability before using such mode. - -@see @ref vkSamplerAddressMode(), @ref vkFilter(), @ref vkSamplerMipmapMode() -*/ -MAGNUM_VK_EXPORT bool hasVkSamplerAddressMode(Magnum::SamplerWrapping wrapping); + * @brief Check availability of a generic sampler wrapping mode + * @m_deprecated_since_latest All generic sampler wrapping modes are available + * in Vulkan. + */ +CORRADE_DEPRECATED("all generic sampler wrapping modes are available in Vulkan") MAGNUM_VK_EXPORT bool hasVkSamplerAddressMode(Magnum::SamplerWrapping wrapping); /** -@brief Convert generic sampler filter mode to Vulkan sampler address mode - -Not all generic sampler wrapping modes have a Vulkan equivalent and this -function expects that given mode is available. Use @ref hasVkSamplerAddressMode() -to query availability of given mode. -@see @ref vkFilter(), @ref vkSamplerAddressMode() -*/ -MAGNUM_VK_EXPORT VkSamplerAddressMode vkSamplerAddressMode(Magnum::SamplerWrapping wrapping); + * @brief @copybrief samplerWrapping() + * @m_deprecated_since_latest Use @ref samplerWrapping() instead. + */ +CORRADE_DEPRECATED("use samplerWrapping() instead") MAGNUM_VK_EXPORT VkSamplerAddressMode vkSamplerAddressMode(Magnum::SamplerWrapping wrapping); -/** @overload */ -template Math::Vector vkSamplerAddressMode(const Math::Vector& wrapping) { +/** + * @brief @copybrief samplerWrapping() + * @m_deprecated_since_latest Use @ref samplerWrapping() instead. + */ +template CORRADE_DEPRECATED("use samplerWrapping() instead") Math::Vector vkSamplerAddressMode(const Math::Vector& wrapping) { Math::Vector out{NoInit}; for(std::size_t i = 0; i != dimensions; ++i) out[i] = vkSamplerAddressMode(wrapping[i]); @@ -161,5 +151,8 @@ template Math::Vector } }} +#else +#error use headers corresponding to the suggested replacement APIs instead +#endif #endif diff --git a/src/Magnum/Vk/Sampler.cpp b/src/Magnum/Vk/Sampler.cpp new file mode 100644 index 000000000..4e2b51cb8 --- /dev/null +++ b/src/Magnum/Vk/Sampler.cpp @@ -0,0 +1,242 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Sampler.h" +#include "SamplerCreateInfo.h" + +#include + +#include "Magnum/Sampler.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Vk/Assert.h" +#include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Result.h" + +namespace Magnum { namespace Vk { + +namespace { + +constexpr SamplerFilter FilterMapping[]{ + SamplerFilter::Nearest, + SamplerFilter::Linear +}; + +constexpr SamplerMipmap SamplerMipmapMapping[]{ + SamplerMipmap::Nearest, /* See samplerMipmap() for details */ + SamplerMipmap::Nearest, + SamplerMipmap::Linear +}; + +constexpr SamplerWrapping SamplerWrappingMapping[]{ + SamplerWrapping::Repeat, + SamplerWrapping::MirroredRepeat, + SamplerWrapping::ClampToEdge, + SamplerWrapping::ClampToBorder, + SamplerWrapping::MirrorClampToEdge +}; + +} + +SamplerFilter samplerFilter(const Magnum::SamplerFilter filter) { + CORRADE_ASSERT(UnsignedInt(filter) < Containers::arraySize(FilterMapping), + "Vk::samplerFilter(): invalid filter" << filter, {}); + return FilterMapping[UnsignedInt(filter)]; +} + +SamplerMipmap samplerMipmap(const Magnum::SamplerMipmap mipmap) { + CORRADE_ASSERT(UnsignedInt(mipmap) < Containers::arraySize(SamplerMipmapMapping), + "Vk::samplerMipmap(): invalid mode" << mipmap, {}); + return SamplerMipmapMapping[UnsignedInt(mipmap)]; +} + +SamplerWrapping samplerWrapping(const Magnum::SamplerWrapping wrapping) { + CORRADE_ASSERT(UnsignedInt(wrapping) < Containers::arraySize(SamplerWrappingMapping), + "Vk::samplerWrapping(): invalid wrapping" << wrapping, {}); + return SamplerWrappingMapping[UnsignedInt(wrapping)]; +} + +template Math::Vector samplerWrapping(const Math::Vector& wrapping) { + Math::Vector out{NoInit}; + for(std::size_t i = 0; i != dimensions; ++i) + out[i] = samplerWrapping(wrapping[i]); + return out; +} + +/* Export needed by MSVC, for others it's enough to have on the declaration in + the header */ +template MAGNUM_VK_EXPORT Math::Vector<1, SamplerWrapping> samplerWrapping(const Math::Vector<1, Magnum::SamplerWrapping>&); +template MAGNUM_VK_EXPORT Math::Vector<2, SamplerWrapping> samplerWrapping(const Math::Vector<2, Magnum::SamplerWrapping>&); +template MAGNUM_VK_EXPORT Math::Vector<3, SamplerWrapping> samplerWrapping(const Math::Vector<3, Magnum::SamplerWrapping>&); + +Debug& operator<<(Debug& debug, const SamplerFilter value) { + debug << "Vk::SamplerFilter" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case Vk::SamplerFilter::value: return debug << "::" << Debug::nospace << #value; + _c(Nearest) + _c(Linear) + #undef _c + /* LCOV_EXCL_STOP */ + } + + /* Vulkan docs have the values in decimal, so not converting to hex */ + return debug << "(" << Debug::nospace << Int(value) << Debug::nospace << ")"; +} + +Debug& operator<<(Debug& debug, const SamplerMipmap value) { + debug << "Vk::SamplerMipmap" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case Vk::SamplerMipmap::value: return debug << "::" << Debug::nospace << #value; + _c(Nearest) + _c(Linear) + #undef _c + /* LCOV_EXCL_STOP */ + } + + /* Vulkan docs have the values in decimal, so not converting to hex */ + return debug << "(" << Debug::nospace << Int(value) << Debug::nospace << ")"; +} + +Debug& operator<<(Debug& debug, const SamplerWrapping value) { + debug << "Vk::SamplerWrapping" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case Vk::SamplerWrapping::value: return debug << "::" << Debug::nospace << #value; + _c(Repeat) + _c(MirroredRepeat) + _c(ClampToEdge) + _c(ClampToBorder) + _c(MirrorClampToEdge) + #undef _c + /* LCOV_EXCL_STOP */ + } + + /* Vulkan docs have the values in decimal, so not converting to hex */ + return debug << "(" << Debug::nospace << Int(value) << Debug::nospace << ")"; +} + +SamplerCreateInfo::SamplerCreateInfo(const Flags flags): _info{} { + _info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + _info.flags = VkDescriptorSetLayoutCreateFlags(flags); + _info.minFilter = VkFilter(SamplerFilter::Nearest); + _info.magFilter = VkFilter(SamplerFilter::Nearest); + /* These are 0, which makes them the obvious candidates, however it's also + helpful in case the texture coordinates are completely off -- with + ClampToEdge (that I wanted to use at first) it would make debugging much + harder as the output could be just a single color in worst cases */ + _info.addressModeU = VkSamplerAddressMode(SamplerWrapping::Repeat); + _info.addressModeV = VkSamplerAddressMode(SamplerWrapping::Repeat); + _info.addressModeW = VkSamplerAddressMode(SamplerWrapping::Repeat); + _info.minLod = -1000.0f; + _info.maxLod = 1000.0f; +} + +SamplerCreateInfo::SamplerCreateInfo(NoInitT) noexcept {} + +SamplerCreateInfo::SamplerCreateInfo(const VkSamplerCreateInfo& info): + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _info(info) {} + +SamplerCreateInfo& SamplerCreateInfo::setMinificationFilter(const SamplerFilter filter, const SamplerMipmap mipmap) { + _info.minFilter = VkFilter(filter); + _info.mipmapMode = VkSamplerMipmapMode(mipmap); + return *this; +} + +SamplerCreateInfo& SamplerCreateInfo::setMinificationFilter(const Magnum::SamplerFilter filter, const Magnum::SamplerMipmap mipmap) { + return setMinificationFilter(samplerFilter(filter), samplerMipmap(mipmap)); +} + +SamplerCreateInfo& SamplerCreateInfo::setMagnificationFilter(const SamplerFilter filter) { + _info.magFilter = VkFilter(filter); + return *this; +} + +SamplerCreateInfo& SamplerCreateInfo::setMagnificationFilter(const Magnum::SamplerFilter filter) { + return setMagnificationFilter(samplerFilter(filter)); +} + +SamplerCreateInfo& SamplerCreateInfo::setWrapping(const Math::Vector3& wrapping) { + _info.addressModeU = VkSamplerAddressMode(wrapping.x()); + _info.addressModeV = VkSamplerAddressMode(wrapping.y()); + _info.addressModeW = VkSamplerAddressMode(wrapping.z()); + return *this; +} + +SamplerCreateInfo& SamplerCreateInfo::setWrapping(const Math::Vector3& wrapping) { + return setWrapping(samplerWrapping(wrapping)); +} + +SamplerCreateInfo& SamplerCreateInfo::setWrapping(const SamplerWrapping wrapping) { + return setWrapping(Math::Vector3{wrapping}); +} + +SamplerCreateInfo& SamplerCreateInfo::setWrapping(const Magnum::SamplerWrapping wrapping) { + return setWrapping(Math::Vector3{wrapping}); +} + +Sampler Sampler::wrap(Device& device, const VkSampler handle, const HandleFlags flags) { + Sampler out{NoCreate}; + out._device = &device; + out._handle = handle; + out._flags = flags; + return out; +} + +Sampler::Sampler(Device& device, const SamplerCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} { + MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateSampler(device, info, nullptr, &_handle)); +} + +Sampler::Sampler(NoCreateT): _device{}, _handle{} {} + +Sampler::Sampler(Sampler&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} { + other._handle = {}; +} + +Sampler::~Sampler() { + if(_handle && (_flags & HandleFlag::DestroyOnDestruction)) + (**_device).DestroySampler(*_device, _handle, nullptr); +} + +Sampler& Sampler::operator=(Sampler&& other) noexcept { + using std::swap; + swap(other._device, _device); + swap(other._handle, _handle); + swap(other._flags, _flags); + return *this; +} + +VkSampler Sampler::release() { + const VkSampler handle = _handle; + _handle = {}; + return handle; +} + +}} diff --git a/src/Magnum/Vk/Sampler.h b/src/Magnum/Vk/Sampler.h new file mode 100644 index 000000000..26ca1d36c --- /dev/null +++ b/src/Magnum/Vk/Sampler.h @@ -0,0 +1,145 @@ +#ifndef Magnum_Vk_Sampler_h +#define Magnum_Vk_Sampler_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::Sampler + * @m_since_latest + */ + +#include "Magnum/Tags.h" +#include "Magnum/Vk/Handle.h" +#include "Magnum/Vk/visibility.h" +#include "Magnum/Vk/Vk.h" +#include "Magnum/Vk/Vulkan.h" + +namespace Magnum { namespace Vk { + +/** +@brief Sampler +@m_since_latest + +Wraps a @type_vk_keyword{Sampler}. + +@section Vk-Sampler-creation Sampler creation + +The default-constructed @ref SamplerCreateInfo uses a conservative setup with +nearest neighbor filtering and will produce valid results with no need to set +up anything else: + +@snippet MagnumVk.cpp Sampler-creation + +Usually, however, you'll want to set up filtering and mip level selection at +least, along with other properties: + +@snippet MagnumVk.cpp Sampler-creation-linear + +*/ +class MAGNUM_VK_EXPORT Sampler { + public: + /** + * @brief Wrap existing Vulkan handle + * @param device Vulkan device the sampler is created on + * @param handle The @type_vk{Sampler} handle + * @param flags Handle flags + * + * The @p handle is expected to be originating from @p device. Unlike + * a sampler created using a constructor, the Vulkan sampler is by + * default not deleted on destruction, use @p flags for different + * behavior. + * @see @ref release() + */ + static Sampler wrap(Device& device, VkSampler handle, HandleFlags flags = {}); + + /** + * @brief Constructor + * @param device Vulkan device to create the sampler on + * @param info Sampler creation info + * + * @see @fn_vk_keyword{CreateSampler} + */ + explicit Sampler(Device& device, const SamplerCreateInfo& info); + + /** + * @brief Construct without creating the sampler + * + * The constructed instance is equivalent to moved-from state. Useful + * in cases where you will overwrite the instance later anyway. Move + * another object over it to make it useful. + */ + explicit Sampler(NoCreateT); + + /** @brief Copying is not allowed */ + Sampler(const Sampler&) = delete; + + /** @brief Move constructor */ + Sampler(Sampler&& other) noexcept; + + /** + * @brief Destructor + * + * Destroys associated @type_vk{Sampler} handle, unless the instance + * was created using @ref wrap() without + * @ref HandleFlag::DestroyOnDestruction specified. + * @see @fn_vk_keyword{DestroySampler}, @ref release() + */ + ~Sampler(); + + /** @brief Copying is not allowed */ + Sampler& operator=(const Sampler&) = delete; + + /** @brief Move assignment */ + Sampler& operator=(Sampler&& other) noexcept; + + /** @brief Underlying @type_vk{Sampler} handle */ + VkSampler handle() { return _handle; } + /** @overload */ + operator VkSampler() { return _handle; } + + /** @brief Handle flags */ + HandleFlags handleFlags() const { return _flags; } + + /** + * @brief Release the underlying Vulkan sampler + * + * Releases ownership of the Vulkan sampler and returns its handle so + * @fn_vk{DestroySampler} is not called on destruction. The internal + * state is then equivalent to moved-from state. + * @see @ref wrap() + */ + VkSampler release(); + + private: + /* Can't be a reference because of the NoCreate constructor */ + Device* _device; + + VkSampler _handle; + HandleFlags _flags; +}; + +}} + +#endif diff --git a/src/Magnum/Vk/SamplerCreateInfo.h b/src/Magnum/Vk/SamplerCreateInfo.h new file mode 100644 index 000000000..15d0256fc --- /dev/null +++ b/src/Magnum/Vk/SamplerCreateInfo.h @@ -0,0 +1,308 @@ +#ifndef Magnum_Vk_SamplerCreateInfo_h +#define Magnum_Vk_SamplerCreateInfo_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::SamplerCreateInfo, enum @ref Magnum::Vk::SamplerFilter, @ref Magnum::Vk::SamplerMipmap, @ref Magnum::Vk::SamplerWrapping, function @ref Magnum::Vk::samplerFilter(), @ref Magnum::Vk::samplerMipmap(), @ref Magnum::Vk::samplerWrapping() + * @m_since_latest + */ + +#include + +#include "Magnum/Tags.h" +#include "Magnum/Vk/visibility.h" +#include "Magnum/Vk/Vk.h" +#include "Magnum/Vk/Vulkan.h" + +namespace Magnum { namespace Vk { + +/** +@brief Texture sampler filtering +@m_since_latest + +Wraps a @type_vk_keyword{Filter}. +@see @ref Magnum::SamplerFilter, @ref samplerFilter(), + @ref SamplerCreateInfo::setMinificationFilter(), + @ref SamplerCreateInfo::setMagnificationFilter() +*/ +enum class SamplerFilter: Int { + /** Nearest neighbor filtering */ + Nearest = VK_FILTER_NEAREST, + + /** Linear interpolation filtering */ + Linear = VK_FILTER_LINEAR +}; + +/** +@debugoperatorenum{SamplerFilter} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, SamplerFilter value); + +/** +@brief Convert a generic sampler filter to Vulkan sampler filter +@m_since_latest + +@see @ref samplerMipmap(), @ref samplerWrapping() +*/ +MAGNUM_VK_EXPORT SamplerFilter samplerFilter(Magnum::SamplerFilter filter); + +/** +@brief Texture sampler mip level selection +@m_since_latest + +Wraps a @type_vk_keyword{SamplerMipmapMode}. +@see @ref Magnum::SamplerMipmap, @ref samplerMipmap(), + @ref SamplerCreateInfo::setMinificationFilter() +*/ +enum class SamplerMipmap: Int { + /** Select nearest mip level */ + Nearest = VK_SAMPLER_MIPMAP_MODE_NEAREST, + + /** Linear interpolation of nearest mip levels */ + Linear = VK_SAMPLER_MIPMAP_MODE_LINEAR +}; + +/** +@debugoperatorenum{SamplerWrapping} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, SamplerWrapping value); + +/** +@brief Convert a generic sampler mipmap mode to Vulkan sampler mipmap mode +@m_since_latest + +Vulkan doesn't support the @ref Magnum::SamplerMipmap::Base value directly, +instead @ref SamplerMipmap::Nearest is used and you have to configure the +sampler to use just a single mipmap level. +@see @ref samplerFilter(), @ref samplerWrapping() +*/ +MAGNUM_VK_EXPORT SamplerMipmap samplerMipmap(Magnum::SamplerMipmap mipmap); + +/** +@brief Texture sampler wrapping +@m_since_latest + +@see @ref Magnum::SamplerWrapping, @ref samplerWrapping(), + @ref SamplerCreateInfo::setWrapping() +*/ +enum class SamplerWrapping: Int { + /** Repeat the texture */ + Repeat = VK_SAMPLER_ADDRESS_MODE_REPEAT, + + /** Repeat a mirrored texture */ + MirroredRepeat = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + + /** + * Clamp to edge. Coordinates out of range will be clamped to the first / + * last column / row / layer in given direction. + */ + ClampToEdge = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + + /** + * Clamp to border color. Coordinates of out range will be clamped to the + * border color. + */ + ClampToBorder = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + + /** + * Mirror the texture once in negative coordinates and clamp to edge after + * that. + * @requires_vk12 Extension @vk_extension{KHR,sampler_mirror_clamp_to_edge} + * @todoc The extension mentions something about vanilla 1.2 not having + * this unless the extension is also listed (wtf??) + */ + MirrorClampToEdge = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE +}; + +/** +@debugoperatorenum{SamplerMipmap} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, SamplerMipmap value); + +/** +@brief Convert a generic sampler wrapping mode to Vulkan sampler wrapping mode +@m_since_latest + +@see @ref samplerFilter(), @ref samplerMipmap() +*/ +MAGNUM_VK_EXPORT SamplerWrapping samplerWrapping(Magnum::SamplerWrapping wrapping); + +/** + * @brief @copybrief samplerWrapping() + * @m_deprecated_since_latest Use @ref samplerWrapping() instead. + */ +template MAGNUM_VK_EXPORT Math::Vector samplerWrapping(const Math::Vector& wrapping); + +/** +@brief Sampler creation info +@m_since_latest + +Wraps a @type_vk_keyword{SamplerCreateInfo}. See +@ref Vk-Sampler-creation "Sampler creation" for usage information. +@todo @type_vk{SamplerReductionMode}, anisotropy +*/ +class MAGNUM_VK_EXPORT SamplerCreateInfo { + public: + /** + * @brief Sampler creation flag + * + * Wraps @type_vk_keyword{SamplerCreateFlagBits}. + * @see @ref Flags, @ref SamplerCreateInfo(Flags) + * @m_enum_values_as_keywords + */ + enum class Flag: UnsignedInt { + /** @todo all the flags from extensions */ + }; + + /** + * @brief Sampler creation flags + * + * Type-safe wrapper for @type_vk_keyword{SamplerCreateFlags}. + * @see @ref SamplerCreateInfo(Flags) + */ + typedef Containers::EnumSet Flags; + + /** + * @brief Constructor + * @param flags Sampler creation flags + * + * The following @type_vk{SamplerCreateInfo} fields are pre-filled in + * addition to `sType`, everything else is zero-filled: + * + * - `flags` + * - `minFilter` and `magFilter` to @ref SamplerFilter::Nearest + * - `mipmapMode` to @ref SamplerMipmap::Nearest + * - `addressModeU`, `addressModeV` and `addressModeW` to + * @ref SamplerWrapping::Repeat + * - `minLod` to @cpp -1000.0f @ce + * - `maxLod` to @cpp 1000.0f @ce + * + * The min/max LOD defaults are chosen to be the same as OpenGL + * defaults. + * @see @ref setMinificationFilter(), @ref setMagnificationFilter(), + * @ref setWrapping() + */ + explicit SamplerCreateInfo(Flags flags = {}); + + /** + * @brief Construct without initializing the contents + * + * Note that not even the `sType` field is set --- the structure has to + * be fully initialized afterwards in order to be usable. + */ + explicit SamplerCreateInfo(NoInitT) noexcept; + + /** + * @brief Construct from existing data + * + * Copies the existing values verbatim, pointers are kept unchanged + * without taking over the ownership. Modifying the newly created + * instance will not modify the original data nor the pointed-to data. + */ + explicit SamplerCreateInfo(const VkSamplerCreateInfo& info); + + /** + * @brief Set minification filter + * @return Reference to self (for method chaining) + * + * Sets the following @type_vk{SamplerCreateInfo} fields: + * + * - `minFilter` to @p filter + * - `mipmapMode` to @p mipmap + * + * @see @ref setMagnificationFilter(), @ref setWrapping() + */ + SamplerCreateInfo& setMinificationFilter(SamplerFilter filter, SamplerMipmap mipmap); + /** @overload */ + SamplerCreateInfo& setMinificationFilter(Magnum::SamplerFilter filter, Magnum::SamplerMipmap mipmap); + + /** + * @brief Set magnification filter + * @return Reference to self (for method chaining) + * + * Sets the following @type_vk{SamplerCreateInfo} fields: + * + * - `magFilter` to @p filter + * + * @see @ref setMinificationFilter(), @ref setWrapping() + */ + SamplerCreateInfo& setMagnificationFilter(SamplerFilter filter); + /** @overload */ + SamplerCreateInfo& setMagnificationFilter(Magnum::SamplerFilter filter); + + /** + * @brief Set wrapping + * @return Reference to self (for method chaining) + * + * Sets the following @type_vk{SamplerCreateInfo} fields: + * + * - `addressModeU`, `addressModeV` and `addressModeW` to + * the respective components of @p wrapping + * + * @see @ref setMinificationFilter(), @ref setMagnificationFilter() + */ + SamplerCreateInfo& setWrapping(const Math::Vector3& wrapping); + /** @overload */ + SamplerCreateInfo& setWrapping(const Math::Vector3& wrapping); + + /** + * @brief Set wrapping for all dimensions at once + * @return Reference to self (for method chaining) + * + * Same as calling @ref setWrapping(const Math::Vector3&) + * with @p wrapping set for all components. + */ + SamplerCreateInfo& setWrapping(SamplerWrapping wrapping); + /** @overload */ + SamplerCreateInfo& setWrapping(Magnum::SamplerWrapping wrapping); + + /** @brief Underlying @type_vk{SamplerCreateInfo} structure */ + VkSamplerCreateInfo& operator*() { return _info; } + /** @overload */ + const VkSamplerCreateInfo& operator*() const { return _info; } + /** @overload */ + VkSamplerCreateInfo* operator->() { return &_info; } + /** @overload */ + const VkSamplerCreateInfo* operator->() const { return &_info; } + /** @overload */ + operator const VkSamplerCreateInfo*() const { return &_info; } + + private: + VkSamplerCreateInfo _info; +}; + +CORRADE_ENUMSET_OPERATORS(SamplerCreateInfo::Flags) + +}} + +/* Make the definition complete -- it doesn't make sense to have a CreateInfo + without the corresponding object anyway. */ +#include "Magnum/Vk/Sampler.h" + +#endif diff --git a/src/Magnum/Vk/Test/CMakeLists.txt b/src/Magnum/Vk/Test/CMakeLists.txt index 7cce44722..7738e9936 100644 --- a/src/Magnum/Vk/Test/CMakeLists.txt +++ b/src/Magnum/Vk/Test/CMakeLists.txt @@ -30,7 +30,6 @@ corrade_add_test(VkCommandPoolTest CommandPoolTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkDeviceTest DeviceTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkDevicePropertiesTest DevicePropertiesTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkDeviceFeaturesTest DeviceFeaturesTest.cpp LIBRARIES MagnumVk) -corrade_add_test(VkEnumsTest EnumsTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkExtensionsTest ExtensionsTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkExtensionPropertiesTest ExtensionPropertiesTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkFenceTest FenceTest.cpp LIBRARIES MagnumVk) @@ -50,6 +49,7 @@ corrade_add_test(VkPixelFormatTest PixelFormatTest.cpp LIBRARIES MagnumVkTestLib corrade_add_test(VkQueueTest QueueTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkResultTest ResultTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkRenderPassTest RenderPassTest.cpp LIBRARIES MagnumVkTestLib) +corrade_add_test(VkSamplerTest SamplerTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkShaderTest ShaderTest.cpp LIBRARIES MagnumVk) target_include_directories(VkShaderTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$) @@ -132,7 +132,6 @@ set_target_properties( VkDeviceTest VkDeviceFeaturesTest VkDevicePropertiesTest - VkEnumsTest VkExtensionsTest VkExtensionPropertiesTest VkFenceTest @@ -152,6 +151,7 @@ set_target_properties( VkQueueTest VkResultTest VkRenderPassTest + VkSamplerTest VkShaderTest VkShaderSetTest VkStructureHelpersTest @@ -226,13 +226,17 @@ if(BUILD_VK_TESTS) LIBRARIES MagnumVkTestLib MagnumVulkanTester FILES triangle-shaders.spv compute-noop.spv) target_include_directories(VkPipelineVkTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$) + corrade_add_test(VkPipelineLayoutVkTest PipelineLayoutVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkQueueVkTest QueueVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkRenderPassVkTest RenderPassVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) + corrade_add_test(VkSamplerVkTest SamplerVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) + corrade_add_test(VkShaderVkTest ShaderVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester FILES triangle-shaders.spv) target_include_directories(VkShaderVkTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$) + corrade_add_test(VkVersionVkTest VersionVkTest.cpp LIBRARIES MagnumVk) set_target_properties( @@ -254,6 +258,7 @@ if(BUILD_VK_TESTS) VkPipelineLayoutVkTest VkQueueVkTest VkRenderPassVkTest + VkSamplerVkTest VkShaderVkTest VkVersionVkTest PROPERTIES FOLDER "Magnum/Vk/Test") diff --git a/src/Magnum/Vk/Test/EnumsTest.cpp b/src/Magnum/Vk/Test/EnumsTest.cpp deleted file mode 100644 index 503f11ef6..000000000 --- a/src/Magnum/Vk/Test/EnumsTest.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - This file is part of Magnum. - - Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, - 2020, 2021 Vladimír Vondruš - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -*/ - -#include -#include -#include - -#include "Magnum/Mesh.h" -#include "Magnum/PixelFormat.h" -#include "Magnum/Sampler.h" -#include "Magnum/VertexFormat.h" -#include "Magnum/Vk/Enums.h" - -namespace Magnum { namespace Vk { namespace Test { namespace { - -struct EnumsTest: TestSuite::Tester { - explicit EnumsTest(); - - void mapVkFilter(); - void mapVkFilterInvalid(); - - void mapVkSamplerMipmapMode(); - void mapVkSamplerMipmapModeInvalid(); - - void mapVkSamplerAddressMode(); - void mapVkSamplerAddressModeArray(); - void mapVkSamplerAddressModeUnsupported(); - void mapVkSamplerAddressModeInvalid(); -}; - -EnumsTest::EnumsTest() { - addTests({&EnumsTest::mapVkFilter, - &EnumsTest::mapVkFilterInvalid, - - &EnumsTest::mapVkSamplerMipmapMode, - &EnumsTest::mapVkSamplerMipmapModeInvalid, - - &EnumsTest::mapVkSamplerAddressMode, - &EnumsTest::mapVkSamplerAddressModeArray, - &EnumsTest::mapVkSamplerAddressModeUnsupported, - &EnumsTest::mapVkSamplerAddressModeInvalid}); -} - -void EnumsTest::mapVkFilter() { - CORRADE_COMPARE(vkFilter(SamplerFilter::Nearest), VK_FILTER_NEAREST); - CORRADE_COMPARE(vkFilter(SamplerFilter::Linear), VK_FILTER_LINEAR); -} - -void EnumsTest::mapVkFilterInvalid() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - std::ostringstream out; - Error redirectError{&out}; - - vkFilter(Magnum::SamplerFilter(0x123)); - CORRADE_COMPARE(out.str(), - "Vk::vkFilter(): invalid filter SamplerFilter(0x123)\n"); -} - -void EnumsTest::mapVkSamplerMipmapMode() { - CORRADE_COMPARE(vkSamplerMipmapMode(SamplerMipmap::Base), VK_SAMPLER_MIPMAP_MODE_NEAREST); /* deliberate */ - CORRADE_COMPARE(vkSamplerMipmapMode(SamplerMipmap::Nearest), VK_SAMPLER_MIPMAP_MODE_NEAREST); - CORRADE_COMPARE(vkSamplerMipmapMode(SamplerMipmap::Linear), VK_SAMPLER_MIPMAP_MODE_LINEAR); -} - -void EnumsTest::mapVkSamplerMipmapModeInvalid() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - std::ostringstream out; - Error redirectError{&out}; - - vkSamplerMipmapMode(Magnum::SamplerMipmap(0x123)); - CORRADE_COMPARE(out.str(), - "Vk::vkSamplerMipmapMode(): invalid mode SamplerMipmap(0x123)\n"); -} - -void EnumsTest::mapVkSamplerAddressMode() { - CORRADE_VERIFY(hasVkSamplerAddressMode(SamplerWrapping::Repeat)); - CORRADE_COMPARE(vkSamplerAddressMode(SamplerWrapping::Repeat), VK_SAMPLER_ADDRESS_MODE_REPEAT); - - CORRADE_VERIFY(hasVkSamplerAddressMode(SamplerWrapping::MirroredRepeat)); - CORRADE_COMPARE(vkSamplerAddressMode(SamplerWrapping::MirroredRepeat), VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT); - - CORRADE_VERIFY(hasVkSamplerAddressMode(SamplerWrapping::ClampToEdge)); - CORRADE_COMPARE(vkSamplerAddressMode(SamplerWrapping::ClampToEdge), VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - - CORRADE_VERIFY(hasVkSamplerAddressMode(SamplerWrapping::ClampToBorder)); - CORRADE_COMPARE(vkSamplerAddressMode(SamplerWrapping::ClampToBorder), VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); -} - -void EnumsTest::mapVkSamplerAddressModeArray() { - CORRADE_COMPARE(vkSamplerAddressMode<2>({SamplerWrapping::Repeat, SamplerWrapping::ClampToBorder}), (Math::Vector2{VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER})); -} - -void EnumsTest::mapVkSamplerAddressModeUnsupported() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - #if 1 - CORRADE_SKIP("All sampler address modes are supported."); - #else - CORRADE_VERIFY(!hasVkSamplerAddressMode(Magnum::SamplerWrapping::MirrorClampToEdge)); - std::ostringstream out; - Error redirectError{&out}; - vkSamplerAddressMode(Magnum::SamplerWrapping::MirrorClampToEdge); - CORRADE_COMPARE(out.str(), - "Vk::vkSamplerAddressMode(): unsupported wrapping SamplerWrapping::MirrorClampToEdge\n"); - #endif -} - -void EnumsTest::mapVkSamplerAddressModeInvalid() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - std::ostringstream out; - Error redirectError{&out}; - - vkSamplerAddressMode(Magnum::SamplerWrapping(0x123)); - CORRADE_COMPARE(out.str(), - "Vk::vkSamplerAddressMode(): invalid wrapping SamplerWrapping(0x123)\n"); -} - -}}}} - -CORRADE_TEST_MAIN(Magnum::Vk::Test::EnumsTest) diff --git a/src/Magnum/Vk/Test/SamplerTest.cpp b/src/Magnum/Vk/Test/SamplerTest.cpp new file mode 100644 index 000000000..25c6a9d37 --- /dev/null +++ b/src/Magnum/Vk/Test/SamplerTest.cpp @@ -0,0 +1,289 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +#include "Magnum/Sampler.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Vk/SamplerCreateInfo.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct SamplerTest: TestSuite::Tester { + explicit SamplerTest(); + + void mapFilter(); + void mapFilterInvalid(); + + void mapMipmap(); + void mapMipmapInvalid(); + + void mapWrapping(); + void mapWrappingVector(); + void mapWrappingInvalid(); + + void createInfoConstruct(); + void createInfoConstructNoInit(); + void createInfoConstructFromVk(); + template void createInfoSetFilter(); + template void createInfoSetMipmap(); + template void createInfoSetWrapping(); + template void createInfoSetWrappingSingleValue(); + + void constructNoCreate(); + void constructCopy(); + + void debugFilter(); + void debugMipmap(); + void debugWrapping(); +}; + +SamplerTest::SamplerTest() { + addTests({&SamplerTest::mapFilter, + &SamplerTest::mapFilterInvalid, + + &SamplerTest::mapMipmap, + &SamplerTest::mapMipmapInvalid, + + &SamplerTest::mapWrapping, + &SamplerTest::mapWrappingVector, + &SamplerTest::mapWrappingInvalid, + + &SamplerTest::createInfoConstruct, + &SamplerTest::createInfoConstructNoInit, + &SamplerTest::createInfoConstructFromVk, + &SamplerTest::createInfoSetFilter, + &SamplerTest::createInfoSetFilter, + &SamplerTest::createInfoSetMipmap, + &SamplerTest::createInfoSetMipmap, + &SamplerTest::createInfoSetWrapping, + &SamplerTest::createInfoSetWrapping, + &SamplerTest::createInfoSetWrappingSingleValue, + &SamplerTest::createInfoSetWrappingSingleValue, + + &SamplerTest::constructNoCreate, + &SamplerTest::constructCopy, + + &SamplerTest::debugFilter, + &SamplerTest::debugMipmap, + &SamplerTest::debugWrapping}); +} + +template struct SamplerTypeTraits; +template<> struct SamplerTypeTraits { + static const char* name() { return "SamplerFilter"; } +}; +template<> struct SamplerTypeTraits { + static const char* name() { return "Magnum::SamplerFilter"; } +}; +template<> struct SamplerTypeTraits { + static const char* name() { return "SamplerMipmap"; } +}; +template<> struct SamplerTypeTraits { + static const char* name() { return "Magnum::SamplerMipmap"; } +}; +template<> struct SamplerTypeTraits { + static const char* name() { return "SamplerWrapping"; } +}; +template<> struct SamplerTypeTraits { + static const char* name() { return "Magnum::SamplerWrapping"; } +}; + +void SamplerTest::mapFilter() { + CORRADE_COMPARE(samplerFilter(Magnum::SamplerFilter::Nearest), SamplerFilter::Nearest); + CORRADE_COMPARE(samplerFilter(Magnum::SamplerFilter::Linear), SamplerFilter::Linear); +} + +void SamplerTest::mapFilterInvalid() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + + samplerFilter(Magnum::SamplerFilter(0x123)); + CORRADE_COMPARE(out.str(), + "Vk::samplerFilter(): invalid filter SamplerFilter(0x123)\n"); +} + +void SamplerTest::mapMipmap() { + CORRADE_COMPARE(samplerMipmap(Magnum::SamplerMipmap::Base), SamplerMipmap::Nearest); /* deliberate */ + CORRADE_COMPARE(samplerMipmap(Magnum::SamplerMipmap::Nearest), SamplerMipmap::Nearest); + CORRADE_COMPARE(samplerMipmap(Magnum::SamplerMipmap::Linear), SamplerMipmap::Linear); +} + +void SamplerTest::mapMipmapInvalid() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + + samplerMipmap(Magnum::SamplerMipmap(0x123)); + CORRADE_COMPARE(out.str(), + "Vk::samplerMipmap(): invalid mode SamplerMipmap(0x123)\n"); +} + +void SamplerTest::mapWrapping() { + CORRADE_COMPARE(samplerWrapping(Magnum::SamplerWrapping::Repeat), SamplerWrapping::Repeat); + + CORRADE_COMPARE(samplerWrapping(Magnum::SamplerWrapping::MirroredRepeat), SamplerWrapping::MirroredRepeat); + + CORRADE_COMPARE(samplerWrapping(Magnum::SamplerWrapping::ClampToEdge), SamplerWrapping::ClampToEdge); + + CORRADE_COMPARE(samplerWrapping(Magnum::SamplerWrapping::ClampToBorder), SamplerWrapping::ClampToBorder); +} + +void SamplerTest::mapWrappingVector() { + CORRADE_COMPARE(samplerWrapping<2>({Magnum::SamplerWrapping::Repeat, Magnum::SamplerWrapping::ClampToBorder}), (Math::Vector2{SamplerWrapping::Repeat, SamplerWrapping::ClampToBorder})); +} + +void SamplerTest::mapWrappingInvalid() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + + samplerWrapping(Magnum::SamplerWrapping(0x123)); + CORRADE_COMPARE(out.str(), + "Vk::samplerWrapping(): invalid wrapping SamplerWrapping(0x123)\n"); +} + +void SamplerTest::createInfoConstruct() { + /** @todo use a real flag once it exists */ + SamplerCreateInfo info{SamplerCreateInfo::Flag(1237)}; + CORRADE_COMPARE(info->flags, 1237); + CORRADE_COMPARE(info->minFilter, VK_FILTER_NEAREST); + CORRADE_COMPARE(info->magFilter, VK_FILTER_NEAREST); + CORRADE_COMPARE(info->mipmapMode, VK_SAMPLER_MIPMAP_MODE_NEAREST); + CORRADE_COMPARE(info->addressModeU, VK_SAMPLER_ADDRESS_MODE_REPEAT); + CORRADE_COMPARE(info->addressModeV, VK_SAMPLER_ADDRESS_MODE_REPEAT); + CORRADE_COMPARE(info->addressModeW, VK_SAMPLER_ADDRESS_MODE_REPEAT); + CORRADE_COMPARE(info->minLod, -1000.0f); + CORRADE_COMPARE(info->maxLod, 1000.0f); +} + +void SamplerTest::createInfoConstructNoInit() { + SamplerCreateInfo info{NoInit}; + info->sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + new(&info) SamplerCreateInfo{NoInit}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); + + CORRADE_VERIFY(std::is_nothrow_constructible::value); + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); +} + +void SamplerTest::createInfoConstructFromVk() { + VkSamplerCreateInfo vkInfo; + vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + + SamplerCreateInfo info{vkInfo}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); +} + +template void SamplerTest::createInfoSetFilter() { + setTestCaseTemplateName(SamplerTypeTraits::name()); + + SamplerCreateInfo info; + info.setMinificationFilter(T::Linear, {}) + .setMagnificationFilter(T::Linear); + CORRADE_COMPARE(info->minFilter, VK_FILTER_LINEAR); + CORRADE_COMPARE(info->mipmapMode, 0); + CORRADE_COMPARE(info->magFilter, VK_FILTER_LINEAR); +} + +template void SamplerTest::createInfoSetMipmap() { + setTestCaseTemplateName(SamplerTypeTraits::name()); + + SamplerCreateInfo info; + info.setMinificationFilter({}, T::Linear); + CORRADE_COMPARE(info->minFilter, 0); + CORRADE_COMPARE(info->mipmapMode, VK_SAMPLER_MIPMAP_MODE_LINEAR); +} + +template void SamplerTest::createInfoSetWrapping() { + setTestCaseTemplateName(SamplerTypeTraits::name()); + + SamplerCreateInfo info; + info.setWrapping({T::MirroredRepeat, T::ClampToEdge, T::MirrorClampToEdge}); + CORRADE_COMPARE(info->addressModeU, VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT); + CORRADE_COMPARE(info->addressModeV, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + CORRADE_COMPARE(info->addressModeW, VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE); +} + +template void SamplerTest::createInfoSetWrappingSingleValue() { + setTestCaseTemplateName(SamplerTypeTraits::name()); + + SamplerCreateInfo info; + info.setWrapping(T::ClampToBorder); + CORRADE_COMPARE(info->addressModeU, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + CORRADE_COMPARE(info->addressModeV, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + CORRADE_COMPARE(info->addressModeW, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); +} + +void SamplerTest::constructNoCreate() { + { + Sampler sampler{NoCreate}; + CORRADE_VERIFY(!sampler.handle()); + } + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); +} + +void SamplerTest::constructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +void SamplerTest::debugFilter() { + std::ostringstream out; + Debug{&out} << SamplerFilter::Linear << SamplerFilter(-10007655); + CORRADE_COMPARE(out.str(), "Vk::SamplerFilter::Linear Vk::SamplerFilter(-10007655)\n"); +} + +void SamplerTest::debugMipmap() { + std::ostringstream out; + Debug{&out} << SamplerMipmap::Linear << SamplerMipmap(-10007655); + CORRADE_COMPARE(out.str(), "Vk::SamplerMipmap::Linear Vk::SamplerMipmap(-10007655)\n"); +} + +void SamplerTest::debugWrapping() { + std::ostringstream out; + Debug{&out} << SamplerWrapping::MirrorClampToEdge << SamplerWrapping(-10007655); + CORRADE_COMPARE(out.str(), "Vk::SamplerWrapping::MirrorClampToEdge Vk::SamplerWrapping(-10007655)\n"); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::SamplerTest) diff --git a/src/Magnum/Vk/Test/SamplerVkTest.cpp b/src/Magnum/Vk/Test/SamplerVkTest.cpp new file mode 100644 index 000000000..c2abac8dd --- /dev/null +++ b/src/Magnum/Vk/Test/SamplerVkTest.cpp @@ -0,0 +1,100 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include "Magnum/Vk/SamplerCreateInfo.h" +#include "Magnum/Vk/Result.h" +#include "Magnum/Vk/VulkanTester.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct SamplerVkTest: VulkanTester { + explicit SamplerVkTest(); + + void construct(); + void constructMove(); + + void wrap(); +}; + +SamplerVkTest::SamplerVkTest() { + addTests({&SamplerVkTest::construct, + &SamplerVkTest::constructMove, + + &SamplerVkTest::wrap}); +} + +void SamplerVkTest::construct() { + { + Sampler fence{device(), SamplerCreateInfo{} + .setMinificationFilter(SamplerFilter::Linear, SamplerMipmap::Linear) + }; + CORRADE_VERIFY(fence.handle()); + CORRADE_COMPARE(fence.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void SamplerVkTest::constructMove() { + Sampler a{device(), SamplerCreateInfo{}}; + VkSampler handle = a.handle(); + + Sampler b = std::move(a); + CORRADE_VERIFY(!a.handle()); + CORRADE_COMPARE(b.handle(), handle); + CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); + + Sampler c{NoCreate}; + c = std::move(b); + CORRADE_VERIFY(!b.handle()); + CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); + CORRADE_COMPARE(c.handle(), handle); + CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); + + CORRADE_VERIFY(std::is_nothrow_move_constructible::value); + CORRADE_VERIFY(std::is_nothrow_move_assignable::value); +} + +void SamplerVkTest::wrap() { + VkSampler fence{}; + CORRADE_COMPARE(Result(device()->CreateSampler(device(), + SamplerCreateInfo{}, + nullptr, &fence)), Result::Success); + + auto wrapped = Sampler::wrap(device(), fence, HandleFlag::DestroyOnDestruction); + CORRADE_COMPARE(wrapped.handle(), fence); + + /* Release the handle again, destroy by hand */ + CORRADE_COMPARE(wrapped.release(), fence); + CORRADE_VERIFY(!wrapped.handle()); + device()->DestroySampler(device(), fence, nullptr); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::SamplerVkTest) diff --git a/src/Magnum/Vk/Vk.h b/src/Magnum/Vk/Vk.h index 2d3fc2810..637502163 100644 --- a/src/Magnum/Vk/Vk.h +++ b/src/Magnum/Vk/Vk.h @@ -119,6 +119,11 @@ class RenderPassCreateInfo; SubpassDependency are useful only to be passed directly to RenderPassCreateInfo */ enum class Result: Int; +class Sampler; +class SamplerCreateInfo; +enum class SamplerFilter: Int; +enum class SamplerMipmap: Int; +enum class SamplerWrapping: Int; class Shader; class ShaderCreateInfo; class ShaderSet;