diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index d3a8574ea..394aa87e5 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -311,6 +311,26 @@ info.setEnabledFeatures(properties.features() & // mask away unsupported ones /* [Device-creation-check-supported] */ } +{ +Vk::Instance instance; +/* [Device-creation-portability-subset] */ +Vk::DeviceProperties properties = DOXYGEN_IGNORE(Vk::pickDevice(instance)); +Vk::Device device{instance, Vk::DeviceCreateInfo{properties} + /* enable triangle fans only if actually supported */ + .setEnabledFeatures(properties.features() & Vk::DeviceFeature::TriangleFans) + DOXYGEN_IGNORE() +}; + +DOXYGEN_IGNORE() + +if(device.enabledFeatures() & Vk::DeviceFeature::TriangleFans) { + // draw a triangle fan mesh +} else { + // indexed draw fallback +} +/* [Device-creation-portability-subset] */ +} + { Vk::Instance instance; VkQueryPool pool{}; diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 2323cfa73..eb522a514 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -571,6 +571,8 @@ Vulkan structure | Matching API @type_vk{PhysicalDeviceMultiviewFeatures} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref DeviceFeatures @type_vk{PhysicalDeviceMultiviewProperties} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{PhysicalDevicePointClippingProperties} @m_class{m-label m-flat m-success} **KHR, 1.1** | | +@type_vk{PhysicalDevicePortabilitySubsetFeaturesKHR} @m_class{m-label m-flat m-warning} **KHR** | @ref DeviceFeatures +@type_vk{PhysicalDevicePortabilitySubsetPropertiesKHR} @m_class{m-label m-flat m-warning} **KHR** | | @type_vk{PhysicalDeviceProperties}, \n @type_vk{PhysicalDeviceProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref DeviceProperties @type_vk{PhysicalDeviceProtectedMemoryFeatures} @m_class{m-label m-flat m-success} **1.1** | @ref DeviceFeatures @type_vk{PhysicalDeviceProtectedMemoryProperties} @m_class{m-label m-flat m-success} **1.1** | | diff --git a/doc/vulkan-support.dox b/doc/vulkan-support.dox index 3e76f713e..28ac33355 100644 --- a/doc/vulkan-support.dox +++ b/doc/vulkan-support.dox @@ -123,6 +123,7 @@ Extension | Status @vk_extension{EXT,vertex_attribute_divisor} | | @vk_extension{EXT,index_type_uint8} | @ref Vk::vkIndexType() only @vk_extension{KHR,acceleration_structure} | | +@vk_extension{KHR,portability_subset} | done except properties @vk_extension{KHR,deferred_host_operations} | | @vk_extension{KHR,pipeline_library} | | @vk_extension{KHR,ray_tracing_pipeline} | | diff --git a/src/Magnum/Vk/Device.cpp b/src/Magnum/Vk/Device.cpp index 3be4aaacb..3d47fb113 100644 --- a/src/Magnum/Vk/Device.cpp +++ b/src/Magnum/Vk/Device.cpp @@ -86,6 +86,15 @@ struct DeviceCreateInfo::State { VkPhysicalDeviceFeatures2 features2{}; Implementation::DeviceFeatures features{}; DeviceFeatures enabledFeatures; + /* Some features are treated as implicitly enabled. Currently this includes + KHR_portability_subset features on devices that *don't* advertise the + extension, in the future it might be for example features unique to + Vulkan1[12]Features (which isn't present in the pNext chain), for which + the corresponding extension got enabled and thus implicitly enabled + those. For all those is common that those don't get explicitly marked as + enabled on device creation and are also not listed among enabled + features in the startup log. */ + DeviceFeatures implicitFeatures; void* firstEnabledFeature{}; /* Used for checking if the device enables extensions required by features */ #ifndef CORRADE_NO_ASSERT @@ -165,6 +174,22 @@ DeviceCreateInfo::DeviceCreateInfo(DeviceProperties& deviceProperties, const Ext if(extensionProperties->isSupported()) addEnabledExtensions(); } + + /* Enable the KHR_portability_subset extension, which *has to be* + enabled when available. Not enabling any of its features though, + that responsibility lies on the user. */ + if(extensionProperties->isSupported()) { + addEnabledExtensions(); + + /* Otherwise, if KHR_portability_subset is not supported, mark its + features as *implicitly* supported -- those don't get explicitly + enabled and are also not listed in the list of enabled features in + the startup log */ + /** @todo wrap this under a NoImplicitFeatures flag? it doesn't actually + *do* anything though */ + } else { + _state->implicitFeatures = Implementation::deviceFeaturesPortabilitySubset(); + } } /* Conservatively populate the device properties. @@ -308,8 +333,14 @@ template void structureConnectIfUsed(Containers::Reference } -DeviceCreateInfo& DeviceCreateInfo::setEnabledFeatures(const DeviceFeatures& features) & { - /* Remember the features to pass them to Device later */ +DeviceCreateInfo& DeviceCreateInfo::setEnabledFeatures(const DeviceFeatures& features_) & { + /* Filter out implicit features as those are treated as being present even + if not explicitly enabled (such as KHR_portability_subset on devices + that *don't* advertise the extension */ + const DeviceFeatures features = features_ & ~_state->implicitFeatures; + + /* Remember the features to pass them to Device later. This gets combined + with implicitFeatures again for Device::enabledFeatures(). */ _state->enabledFeatures = features; /* Clear any existing pointers to the feature structure chain. This needs @@ -346,6 +377,7 @@ DeviceCreateInfo& DeviceCreateInfo::setEnabledFeatures(const DeviceFeatures& fea _state->features.accelerationStructure, _state->features.samplerYcbcrConversion, _state->features.descriptorIndexing, + _state->features.portabilitySubset, _state->features.shaderSubgroupExtendedTypes, _state->features._8BitStorage, _state->features.shaderAtomicInt64, @@ -451,6 +483,8 @@ DeviceCreateInfo& DeviceCreateInfo::setEnabledFeatures(const DeviceFeatures& fea _state->features.samplerYcbcrConversion, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES); structureConnectIfUsed(next, _state->firstEnabledFeature, _state->features.descriptorIndexing, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES); + structureConnectIfUsed(next, _state->firstEnabledFeature, + _state->features.portabilitySubset, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR); structureConnectIfUsed(next, _state->firstEnabledFeature, _state->features.shaderSubgroupExtendedTypes, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES); structureConnectIfUsed(next, _state->firstEnabledFeature, @@ -652,7 +686,10 @@ Result Device::tryCreateInternal(Instance& instance, const DeviceCreateInfo& inf const Version version = info._state->version != Version::None ? info._state->version : _properties->version(); - /* Print all enabled extensions if we're not told to be quiet */ + /* Print all enabled extensions and features if we're not told to be quiet. + The implicit features (such as KHR_portability_subset features on + devices that *don't* advertise the extension) are not listed here but + are added to Device::enabledFeatures() below. */ if(!info._state->quietLog) { Debug{} << "Device:" << _properties->name(); Debug{} << "Device version:" << version; @@ -678,7 +715,7 @@ Result Device::tryCreateInternal(Instance& instance, const DeviceCreateInfo& inf } initializeExtensions({info->ppEnabledExtensionNames, info->enabledExtensionCount}); - initialize(instance, version, info._state->enabledFeatures); + initialize(instance, version, info._state->enabledFeatures | info._state->implicitFeatures); #ifndef CORRADE_NO_ASSERT /* This is a dumb O(n^2) search but in an assert that's completely fine */ diff --git a/src/Magnum/Vk/Device.h b/src/Magnum/Vk/Device.h index 7468e782e..967c7148b 100644 --- a/src/Magnum/Vk/Device.h +++ b/src/Magnum/Vk/Device.h @@ -115,6 +115,33 @@ explicitly enabled. With both @ref Instance and @ref Device created, you can proceed to setting up a @ref CommandPool. +@subsection Vk-Device-portability-subset Vulkan portability subset + +To simplify porting to platforms with the Portability Subset, Magnum implicitly +enables the @vk_extension{KHR,portability_subset} extension on all devices that +advertise it, as required by the spec, so you don't need to handle that part. +This behavior can be disabled with +@ref DeviceCreateInfo::Flag::NoImplicitExtensions. + +For portability-related @ref DeviceFeatures, on conformant Vulkan +implementations (which don't advertise @vk_extension{KHR,portability_subset}) +these are all implicitly marked as supported in @ref DeviceProperties::features() +and then implicitly marked as enabled in @ref Device::enabledFeatures(), +independently of whether you enable them or not. On devices having only the +Portability Subset, the supported features are listed in +@ref DeviceProperties::features() but you're expected to manually enable them +on device creation --- that part is *not done implicitly* by the engine. + +A workflow that supports both conformant and Portability Subset devices with a +single code path is outlined in the following snippet --- on device creation +you request features that you want (which is a no-op on conformant +implementations), and at runtime you query those features in appropriate cases +(which will be always @cpp true @ce on conformant implementations). As with +other features, all APIs that require a particular Portability Subset feature +are marked as such and also listed among others at @ref requires-vk-feature. + +@snippet MagnumVk.cpp Device-creation-portability-subset + @see @ref vulkan-wrapping-optimizing-properties @section Vk-Device-command-line Command-line options diff --git a/src/Magnum/Vk/DeviceCreateInfo.h b/src/Magnum/Vk/DeviceCreateInfo.h index 968443068..4ac8e8761 100644 --- a/src/Magnum/Vk/DeviceCreateInfo.h +++ b/src/Magnum/Vk/DeviceCreateInfo.h @@ -69,6 +69,12 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo { * @vk_extension{KHR,get_memory_requirements2} to provide a broader * functionality. If you want to have a complete control over what * gets enabled, set this flag. + * + * This flag also affects enabling of + * @vk_extension{KHR,portability_subset},which is *required* to be + * enabled by the spec on any device that advertises it, and + * behavior of related @ref DeviceFeatures. See + * @ref Vk-Device-portability-subset for details. */ NoImplicitExtensions = 1u << 31 }; @@ -234,6 +240,8 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo { * (Vulkan 1.1, @vk_extension{KHR,sampler_ycbcr_conversion}) * - @type_vk_keyword{PhysicalDeviceDescriptorIndexingFeatures} * (Vulkan 1.2, @vk_extension{EXT,descriptor_indexing}) + * - @type_vk_keyword{PhysicalDevicePortabilitySubsetFeaturesKHR} + * (@vk_extension{KHR,portability_subset}) * - @type_vk_keyword{PhysicalDeviceShaderSubgroupExtendedTypesFeatures} * (Vulkan 1.2, @vk_extension{KHR,shader_subgroup_extended_types}) * - @type_vk_keyword{PhysicalDevice8BitStorageFeatures} (Vulkan diff --git a/src/Magnum/Vk/DeviceFeatures.h b/src/Magnum/Vk/DeviceFeatures.h index 76b2a4afb..3ac3756e8 100644 --- a/src/Magnum/Vk/DeviceFeatures.h +++ b/src/Magnum/Vk/DeviceFeatures.h @@ -880,6 +880,121 @@ enum class DeviceFeature: UnsignedShort { */ RuntimeDescriptorArray, + /* VkPhysicalDevicePortabilitySubsetFeaturesKHR, #164 */ + + /** + * Whether constant alpha as source or destination blend color is + * supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + ConstantAlphaColorBlendFactors, + + /** + * Whether synchronization using events is supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + Events, + + /** + * Whether an @ref ImageView can be created with a format containing + * different number of components or a different number of bits in each + * component than the format of the underlying @ref Image. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + ImageViewFormatReinterpretation, + + /** + * Whether remapping format components in an @ref ImageView is supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + ImageViewFormatSwizzle, + + /** + * Whether a 2D view can be created on a 3D @ref Image can be created. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + ImageView2DOn3DImage, + + /** + * Whether multisample 2D array @ref Image can be created. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + MultisampleArrayImage, + + /** + * Whether descriptors with comparison samplers can be updated. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + MutableComparisonSamplers, + + /** + * Whether rasterization using a point polygon mode is supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + PointPolygons, + + /** + * Whether setting a mipmap LOD bias when creating a sampler is supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + SamplerMipLodBias, + + /** + * Whether separate front and back stencil test reference values are + * supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + SeparateStencilMaskRef, + + /** + * Whether interpolation at centroid, offset and sample is supported. + * Depends on @ref DeviceFeature::SampleRateShading. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + ShaderSampleRateInterpolationFunctions, + + /** + * Whether isoline output from a tessellation shader stage is supported. + * Depends on @ref DeviceFeature::TessellationShader. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + TessellationIsolines, + + /** + * Whether point output from a tessellation shader stage is supported. + * Depends on @ref DeviceFeature::TessellationShader. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + TessellationPointMode, + + /** + * Whether triangle fan mesh primitives are supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + TriangleFans, + + /** + * Whether accessing a vertex input attribute beyond the stride of + * corresponding vertex input binding is supported. + * @requires_vk_extension Extension @vk_extension{KHR,portability_subset}, + * see @ref Vk-Device-portability-subset for details. + */ + VertexAttributeAccessBeyondStride, + /* VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures, #176 */ /** diff --git a/src/Magnum/Vk/DeviceProperties.cpp b/src/Magnum/Vk/DeviceProperties.cpp index 3f500969f..272b5f07f 100644 --- a/src/Magnum/Vk/DeviceProperties.cpp +++ b/src/Magnum/Vk/DeviceProperties.cpp @@ -309,6 +309,10 @@ const DeviceFeatures& DeviceProperties::features() { Implementation::structureConnect(next, features.samplerYcbcrConversion, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES); if(isOrVersionSupportedInternal()) Implementation::structureConnect(next, features.descriptorIndexing, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES); + /* See below as well -- the features are implicitly marked as supported + if the KHR_portability_subset extension is *not* present */ + if(isOrVersionSupportedInternal()) + Implementation::structureConnect(next, features.portabilitySubset, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR); if(isOrVersionSupportedInternal()) Implementation::structureConnect(next, features.shaderSubgroupExtendedTypes, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES); if(isOrVersionSupportedInternal()) @@ -351,6 +355,11 @@ const DeviceFeatures& DeviceProperties::features() { #undef _c #undef _cver #undef _cext + + /* If the KHR_portability_subset extension is not present, its features + are marked as being implicitly supported */ + if(!isOrVersionSupportedInternal()) + _state->features |= Implementation::deviceFeaturesPortabilitySubset(); } return _state->features; diff --git a/src/Magnum/Vk/DeviceProperties.h b/src/Magnum/Vk/DeviceProperties.h index fb39dba34..d20afb703 100644 --- a/src/Magnum/Vk/DeviceProperties.h +++ b/src/Magnum/Vk/DeviceProperties.h @@ -451,6 +451,9 @@ class MAGNUM_VK_EXPORT DeviceProperties { * - If Vulkan 1.2 or the @vk_extension{EXT,descriptor_indexing} * extension is supported by the device, the `pNext` chain * contains @type_vk_keyword{PhysicalDeviceDescriptorIndexingFeatures} + * - If the @vk_extension{KHR,portability_subset} extension is + * supported by the device, the `pNext` chain contains + * @type_vk_keyword{PhysicalDevicePortabilitySubsetFeaturesKHR} * - If Vulkan 1.2 or the @vk_extension{KHR,shader_subgroup_extended_types} * extension is supported by the device, the `pNext` chain * contains @type_vk_keyword{PhysicalDeviceShaderSubgroupExtendedTypesFeatures} @@ -493,6 +496,11 @@ class MAGNUM_VK_EXPORT DeviceProperties { * the device, the `pNext` chain contains * @type_vk_keyword{PhysicalDeviceRayQueryFeaturesKHR} * + * If the @vk_extension{KHR,portability_subset} is *not* supported by + * the device, all features related to it are implicitly marked as + * supported to simplify portability-aware logic. See + * @ref Vk-Device-portability-subset for details. + * * @see @ref Device::enabledFeatures(), * @fn_vk_keyword{GetPhysicalDeviceFeatures2}, * @fn_vk_keyword{GetPhysicalDeviceFeatures}, diff --git a/src/Magnum/Vk/Extensions.cpp b/src/Magnum/Vk/Extensions.cpp index aebb89ccb..81cba9d0a 100644 --- a/src/Magnum/Vk/Extensions.cpp +++ b/src/Magnum/Vk/Extensions.cpp @@ -75,6 +75,7 @@ constexpr Extension DeviceExtensions[] { Extensions::KHR::acceleration_structure{}, Extensions::KHR::deferred_host_operations{}, Extensions::KHR::pipeline_library{}, + Extensions::KHR::portability_subset{}, Extensions::KHR::ray_query{}, Extensions::KHR::ray_tracing_pipeline{}, }; diff --git a/src/Magnum/Vk/Extensions.h b/src/Magnum/Vk/Extensions.h index df7e551f8..8a61cab2e 100644 --- a/src/Magnum/Vk/Extensions.h +++ b/src/Magnum/Vk/Extensions.h @@ -149,24 +149,25 @@ namespace EXT { _extension(50, KHR,acceleration_structure, Vk11, None) // #151 _extension(51, KHR,sampler_ycbcr_conversion, Vk10, Vk11) // #157 _extension(52, KHR,bind_memory2, Vk10, Vk11) // #158 - _extension(53, KHR,maintenance3, Vk10, Vk11) // #169 - _extension(54, KHR,draw_indirect_count, Vk10, Vk12) // #170 - _extension(55, KHR,shader_subgroup_extended_types, Vk11, Vk12) // #176 - _extension_(56, KHR,8bit_storage,_8bit_storage, Vk10, Vk12) // #178 - _extension(57, KHR,shader_atomic_int64, Vk10, Vk12) // #181 - _extension(58, KHR,driver_properties, Vk10, Vk12) // #197 - _extension(59, KHR,shader_float_controls, Vk10, Vk12) // #198 - _extension(60, KHR,depth_stencil_resolve, Vk10, Vk12) // #200 - _extension(61, KHR,timeline_semaphore, Vk10, Vk12) // #208 - _extension(62, KHR,vulkan_memory_model, Vk10, Vk12) // #212 - _extension(63, KHR,spirv_1_4, Vk11, Vk12) // #237 - _extension(64, KHR,separate_depth_stencil_layouts, Vk10, Vk12) // #242 - _extension(65, KHR,uniform_buffer_standard_layout, Vk10, Vk12) // #254 - _extension(66, KHR,buffer_device_address, Vk10, Vk12) // #258 - _extension(67, KHR,deferred_host_operations, Vk10, None) // #259 - _extension(68, KHR,pipeline_library, Vk10, None) // #291 - _extension(69, KHR,ray_tracing_pipeline, Vk11, None) // #348 - _extension(70, KHR,ray_query, Vk11, None) // #349 + _extension(53, KHR,portability_subset, Vk10, None) // #164 + _extension(54, KHR,maintenance3, Vk10, Vk11) // #169 + _extension(55, KHR,draw_indirect_count, Vk10, Vk12) // #170 + _extension(56, KHR,shader_subgroup_extended_types, Vk11, Vk12) // #176 + _extension_(57, KHR,8bit_storage,_8bit_storage, Vk10, Vk12) // #178 + _extension(58, KHR,shader_atomic_int64, Vk10, Vk12) // #181 + _extension(59, KHR,driver_properties, Vk10, Vk12) // #197 + _extension(60, KHR,shader_float_controls, Vk10, Vk12) // #198 + _extension(61, KHR,depth_stencil_resolve, Vk10, Vk12) // #200 + _extension(62, KHR,timeline_semaphore, Vk10, Vk12) // #208 + _extension(63, KHR,vulkan_memory_model, Vk10, Vk12) // #212 + _extension(64, KHR,spirv_1_4, Vk11, Vk12) // #237 + _extension(65, KHR,separate_depth_stencil_layouts, Vk10, Vk12) // #242 + _extension(66, KHR,uniform_buffer_standard_layout, Vk10, Vk12) // #254 + _extension(67, KHR,buffer_device_address, Vk10, Vk12) // #258 + _extension(68, KHR,deferred_host_operations, Vk10, None) // #259 + _extension(69, KHR,pipeline_library, Vk10, None) // #291 + _extension(70, KHR,ray_tracing_pipeline, Vk11, None) // #348 + _extension(71, KHR,ray_query, Vk11, None) // #349 } #undef _extension diff --git a/src/Magnum/Vk/Implementation/DeviceFeatures.h b/src/Magnum/Vk/Implementation/DeviceFeatures.h index 37da13e1f..687f29947 100644 --- a/src/Magnum/Vk/Implementation/DeviceFeatures.h +++ b/src/Magnum/Vk/Implementation/DeviceFeatures.h @@ -47,6 +47,7 @@ struct DeviceFeatures { VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructure; VkPhysicalDeviceSamplerYcbcrConversionFeatures samplerYcbcrConversion; VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexing; + VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilitySubset; VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures shaderSubgroupExtendedTypes; VkPhysicalDevice8BitStorageFeatures _8BitStorage; VkPhysicalDeviceShaderAtomicInt64Features shaderAtomicInt64; @@ -63,6 +64,25 @@ struct DeviceFeatures { VkPhysicalDeviceRayQueryFeaturesKHR rayQuery; }; +constexpr Vk::DeviceFeatures deviceFeaturesPortabilitySubset() { + return + DeviceFeature::ConstantAlphaColorBlendFactors| + DeviceFeature::Events| + DeviceFeature::ImageViewFormatReinterpretation| + DeviceFeature::ImageViewFormatSwizzle| + DeviceFeature::ImageView2DOn3DImage| + DeviceFeature::MultisampleArrayImage| + DeviceFeature::MutableComparisonSamplers| + DeviceFeature::PointPolygons| + DeviceFeature::SamplerMipLodBias| + DeviceFeature::SeparateStencilMaskRef| + DeviceFeature::ShaderSampleRateInterpolationFunctions| + DeviceFeature::TessellationIsolines| + DeviceFeature::TessellationPointMode| + DeviceFeature::TriangleFans| + DeviceFeature::VertexAttributeAccessBeyondStride; +} + }}} #endif diff --git a/src/Magnum/Vk/Implementation/deviceFeatureMapping.hpp b/src/Magnum/Vk/Implementation/deviceFeatureMapping.hpp index 0247dd4fd..7d2366f93 100644 --- a/src/Magnum/Vk/Implementation/deviceFeatureMapping.hpp +++ b/src/Magnum/Vk/Implementation/deviceFeatureMapping.hpp @@ -155,6 +155,24 @@ _ce(DescriptorBindingVariableDescriptorCount, descriptorBindingVariableDescripto _ce(RuntimeDescriptorArray, runtimeDescriptorArray) #undef _ce +#define _ce(value, field) _cext(value, field, portabilitySubset, KHR::portability_subset) +_ce(ConstantAlphaColorBlendFactors, constantAlphaColorBlendFactors) +_ce(Events, events) +_ce(ImageViewFormatReinterpretation, imageViewFormatReinterpretation) +_ce(ImageViewFormatSwizzle, imageViewFormatSwizzle) +_ce(ImageView2DOn3DImage, imageView2DOn3DImage) +_ce(MultisampleArrayImage, multisampleArrayImage) +_ce(MutableComparisonSamplers, mutableComparisonSamplers) +_ce(PointPolygons, pointPolygons) +_ce(SamplerMipLodBias, samplerMipLodBias) +_ce(SeparateStencilMaskRef, separateStencilMaskRef) +_ce(ShaderSampleRateInterpolationFunctions, shaderSampleRateInterpolationFunctions) +_ce(TessellationIsolines, tessellationIsolines) +_ce(TessellationPointMode, tessellationPointMode) +_ce(TriangleFans, triangleFans) +_ce(VertexAttributeAccessBeyondStride, vertexAttributeAccessBeyondStride) +#undef _ce + _cext(ShaderSubgroupExtendedTypes, shaderSubgroupExtendedTypes, shaderSubgroupExtendedTypes, KHR::shader_subgroup_extended_types) #define _ce(value, field) _cext(value, field, _8BitStorage, KHR::_8bit_storage) diff --git a/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp b/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp index 01ddfa246..0b844d1f3 100644 --- a/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp +++ b/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp @@ -44,6 +44,9 @@ #include "Magnum/Vk/Version.h" #include "Magnum/Vk/VulkanTester.h" +#include "Magnum/Vk/Implementation/DeviceFeatures.h" + /* for deviceFeaturesPortabilitySubset() */ + namespace Magnum { namespace Vk { namespace Test { namespace { struct DevicePropertiesVkTest: VulkanTester { @@ -66,6 +69,8 @@ struct DevicePropertiesVkTest: VulkanTester { void driverProperties(); void features(); + void featuresNoPortability(); + void featuresPortability(); void featureExpectedSupported(); void featureExpectedUnsupported(); @@ -118,6 +123,8 @@ DevicePropertiesVkTest::DevicePropertiesVkTest(): VulkanTester{NoCreate} { &DevicePropertiesVkTest::driverProperties, &DevicePropertiesVkTest::features, + &DevicePropertiesVkTest::featuresNoPortability, + &DevicePropertiesVkTest::featuresPortability, &DevicePropertiesVkTest::featureExpectedSupported, &DevicePropertiesVkTest::featureExpectedUnsupported, @@ -254,6 +261,34 @@ void DevicePropertiesVkTest::features() { } } +void DevicePropertiesVkTest::featuresNoPortability() { + Containers::Optional device = tryPickDevice(instance()); + CORRADE_VERIFY(device); + + if(device->enumerateExtensionProperties().isSupported()) + CORRADE_SKIP("KHR_portability_subset supported, can't test"); + + /* All features should be marked as supported */ + CORRADE_COMPARE_AS(device->features(), Implementation::deviceFeaturesPortabilitySubset(), + TestSuite::Compare::GreaterOrEqual); +} + +void DevicePropertiesVkTest::featuresPortability() { + Containers::Optional device = tryPickDevice(instance()); + CORRADE_VERIFY(device); + + if(!device->enumerateExtensionProperties().isSupported()) + CORRADE_SKIP("KHR_portability_subset not supported, can't test"); + + Debug{} << "Supported portability subset:" << (device->features() & Implementation::deviceFeaturesPortabilitySubset()); + + /* Not all features should be marked as supported */ + CORRADE_VERIFY((device->features() & Implementation::deviceFeaturesPortabilitySubset()) != Implementation::deviceFeaturesPortabilitySubset()); + + /* But there should be at least one */ + CORRADE_VERIFY(device->features() & Implementation::deviceFeaturesPortabilitySubset()); +} + void DevicePropertiesVkTest::featureExpectedSupported() { Containers::Optional device = tryPickDevice(instance()); CORRADE_VERIFY(device); diff --git a/src/Magnum/Vk/Test/DeviceVkTest.cpp b/src/Magnum/Vk/Test/DeviceVkTest.cpp index 60166b54e..b4d9372b2 100644 --- a/src/Magnum/Vk/Test/DeviceVkTest.cpp +++ b/src/Magnum/Vk/Test/DeviceVkTest.cpp @@ -43,6 +43,9 @@ #include "Magnum/Vk/Version.h" #include "Magnum/Vk/VulkanTester.h" +#include "Magnum/Vk/Implementation/DeviceFeatures.h" + /* for deviceFeaturesPortabilitySubset() */ + #include "MagnumExternal/Vulkan/flextVkGlobal.h" namespace Magnum { namespace Vk { namespace Test { namespace { @@ -80,6 +83,10 @@ struct DeviceVkTest: VulkanTester { void constructFeatureWithoutExtension(); void constructNoQueue(); + void constructNoPortability(); + void constructNoPortabilityEnablePortabilityFeatures(); + void constructPortability(); + void tryCreateAlreadyCreated(); void tryCreateUnknownExtension(); @@ -178,6 +185,10 @@ DeviceVkTest::DeviceVkTest(): VulkanTester{NoCreate} { &DeviceVkTest::constructFeatureWithoutExtension, &DeviceVkTest::constructNoQueue, + &DeviceVkTest::constructNoPortability, + &DeviceVkTest::constructNoPortabilityEnablePortabilityFeatures, + &DeviceVkTest::constructPortability, + &DeviceVkTest::tryCreateAlreadyCreated, &DeviceVkTest::tryCreateUnknownExtension, @@ -631,8 +642,10 @@ void DeviceVkTest::constructFeatures() { .setEnabledFeatures(DeviceFeature::RobustBufferAccess)}; CORRADE_VERIFY(device.handle()); - /* Features should be reported as enabled */ - CORRADE_COMPARE(device.enabledFeatures(), DeviceFeature::RobustBufferAccess); + /* Features should be reported as enabled. Exclude portability subset + features that get implicitly marked as enabled on devices w/o + KHR_portability_subset. */ + CORRADE_COMPARE(device.enabledFeatures() & ~Implementation::deviceFeaturesPortabilitySubset(), DeviceFeature::RobustBufferAccess); } void DeviceVkTest::constructFeaturesFromExtensions() { @@ -652,8 +665,10 @@ void DeviceVkTest::constructFeaturesFromExtensions() { .setEnabledFeatures(DeviceFeature::RobustBufferAccess|DeviceFeature::SamplerYcbcrConversion)}; CORRADE_VERIFY(device.handle()); - /* Features should be reported as enabled */ - CORRADE_COMPARE(device.enabledFeatures(), DeviceFeature::RobustBufferAccess|DeviceFeature::SamplerYcbcrConversion); + /* Features should be reported as enabled. Exclude portability subset + features that get implicitly marked as enabled on devices w/o + KHR_portability_subset. */ + CORRADE_COMPARE(device.enabledFeatures() & ~Implementation::deviceFeaturesPortabilitySubset(), DeviceFeature::RobustBufferAccess|DeviceFeature::SamplerYcbcrConversion); } void DeviceVkTest::constructDeviceCreateInfoConstReference() { @@ -923,6 +938,73 @@ void DeviceVkTest::constructNoQueue() { CORRADE_COMPARE(out.str(), "Vk::Device::tryCreate(): needs at least one queue\n"); } +void DeviceVkTest::constructNoPortability() { + DeviceProperties properties = pickDevice(instance()); + + if(properties.enumerateExtensionProperties().isSupported()) + CORRADE_SKIP("KHR_portability_subset supported, can't test"); + + Queue queue{NoCreate}; + Device device{instance(), DeviceCreateInfo{properties} + .addQueues(0, {0.0f}, {queue}) + }; + + /* The extension shouldn't be registered as enabled */ + CORRADE_VERIFY(!device.isExtensionEnabled()); + + /* All features should be marked as enabled */ + CORRADE_COMPARE_AS(device.enabledFeatures(), Implementation::deviceFeaturesPortabilitySubset(), + TestSuite::Compare::GreaterOrEqual); +} + +void DeviceVkTest::constructNoPortabilityEnablePortabilityFeatures() { + DeviceProperties properties = pickDevice(instance()); + + if(properties.enumerateExtensionProperties().isSupported()) + CORRADE_SKIP("KHR_portability_subset supported, can't test"); + + Device device{NoCreate}; + + /* Explicitly enabling portability subset features shouldn't do anything + when the portability extension isn't present */ + Queue queue{NoCreate}; + CORRADE_COMPARE(device.tryCreate(instance(), DeviceCreateInfo{properties} + .addQueues(0, {0.0f}, {queue}) + .setEnabledFeatures(Implementation::deviceFeaturesPortabilitySubset()) + ), Result::Success); + + /* All features should be marked as enabled */ + CORRADE_COMPARE_AS(device.enabledFeatures(), Implementation::deviceFeaturesPortabilitySubset(), + TestSuite::Compare::GreaterOrEqual); +} + +void DeviceVkTest::constructPortability() { + DeviceProperties properties = pickDevice(instance()); + + if(!properties.enumerateExtensionProperties().isSupported()) + CORRADE_SKIP("KHR_portability_subset not supported, can't test"); + + /* (Same as in DevicePropertiesVkTest.) Not all features should be marked + as supported... */ + CORRADE_VERIFY((properties.features() & Implementation::deviceFeaturesPortabilitySubset()) != Implementation::deviceFeaturesPortabilitySubset()); + + /* ... but there should be at least one feature */ + CORRADE_VERIFY(properties.features() & +Implementation::deviceFeaturesPortabilitySubset()); + + Queue queue{NoCreate}; + Device device{instance(), DeviceCreateInfo{properties} + .addQueues(0, {0.0f}, {queue}) + .setEnabledFeatures(properties.features() & +Implementation::deviceFeaturesPortabilitySubset()) + }; + + /* All requested features should be marked as enabled */ + CORRADE_COMPARE_AS(device.enabledFeatures(), properties.features() & +Implementation::deviceFeaturesPortabilitySubset(), + TestSuite::Compare::GreaterOrEqual); +} + void DeviceVkTest::tryCreateAlreadyCreated() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); diff --git a/src/MagnumExternal/Vulkan/extensions.txt b/src/MagnumExternal/Vulkan/extensions.txt index 6e1d721d2..a631d97f1 100644 --- a/src/MagnumExternal/Vulkan/extensions.txt +++ b/src/MagnumExternal/Vulkan/extensions.txt @@ -65,6 +65,7 @@ extension EXT_vertex_attribute_divisor optional extension EXT_index_type_uint8 optional extension IMG_format_pvrtc optional extension KHR_acceleration_structure optional +extension KHR_portability_subset optional extension KHR_deferred_host_operations optional extension KHR_pipeline_library optional extension KHR_ray_tracing_pipeline optional diff --git a/src/MagnumExternal/Vulkan/flextVk.h b/src/MagnumExternal/Vulkan/flextVk.h index 728f32547..8b083deb1 100644 --- a/src/MagnumExternal/Vulkan/flextVk.h +++ b/src/MagnumExternal/Vulkan/flextVk.h @@ -274,6 +274,11 @@ extern "C" { #define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 11 #define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" +/* VK_KHR_portability_subset */ + +#define VK_KHR_PORTABILITY_SUBSET_SPEC_VERSION 1 +#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset" + /* VK_KHR_pipeline_library */ #define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 @@ -1555,6 +1560,8 @@ typedef enum { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR = 1000163000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR = 1000163001, VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, @@ -4721,6 +4728,32 @@ typedef struct VkCopyMemoryToAccelerationStructureInfoKHR { VkCopyAccelerationStructureModeKHR mode; } VkCopyMemoryToAccelerationStructureInfoKHR; +typedef struct VkPhysicalDevicePortabilitySubsetFeaturesKHR { + VkStructureType sType; + void* pNext; + VkBool32 constantAlphaColorBlendFactors; + VkBool32 events; + VkBool32 imageViewFormatReinterpretation; + VkBool32 imageViewFormatSwizzle; + VkBool32 imageView2DOn3DImage; + VkBool32 multisampleArrayImage; + VkBool32 mutableComparisonSamplers; + VkBool32 pointPolygons; + VkBool32 samplerMipLodBias; + VkBool32 separateStencilMaskRef; + VkBool32 shaderSampleRateInterpolationFunctions; + VkBool32 tessellationIsolines; + VkBool32 tessellationPointMode; + VkBool32 triangleFans; + VkBool32 vertexAttributeAccessBeyondStride; +} VkPhysicalDevicePortabilitySubsetFeaturesKHR; + +typedef struct VkPhysicalDevicePortabilitySubsetPropertiesKHR { + VkStructureType sType; + void* pNext; + uint32_t minVertexInputBindingStrideAlignment; +} VkPhysicalDevicePortabilitySubsetPropertiesKHR; + typedef struct VkAccelerationStructureBuildSizesInfoKHR { VkStructureType sType; const void* pNext;