Support the VK_EXT_texel_buffer_alignment extension.

This extension lets implementations report separate limits for uniform
and storage texel buffers, as well as whether or not the required
alignment is only a single texel of the buffer view's format.

This information is available in Metal, but only through an API query.
We must query the required alignment for every buffer view format we
support.

Update Vulkan-Headers to pull in support for this new extension.
This commit is contained in:
Chip Davis 2019-07-15 22:31:03 -05:00
parent fe3b2fbd5f
commit 7771b00bee
8 changed files with 132 additions and 17 deletions

View File

@ -253,12 +253,13 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following
- `VK_EXT_debug_report` - `VK_EXT_debug_report`
- `VK_EXT_debug_utils` - `VK_EXT_debug_utils`
- `VK_EXT_host_query_reset` - `VK_EXT_host_query_reset`
- `VK_EXT_memory_budget` - `VK_EXT_memory_budget` *(requires Metal 2.0)*
- `VK_EXT_metal_surface` - `VK_EXT_metal_surface`
- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)* - `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
- `VK_EXT_shader_viewport_index_layer` - `VK_EXT_shader_viewport_index_layer`
- `VK_EXT_swapchain_colorspace` *(macOS)* - `VK_EXT_swapchain_colorspace` *(macOS)*
- `VK_EXT_vertex_attribute_divisor` - `VK_EXT_vertex_attribute_divisor`
- `VK_EXT_texel_buffer_alignment` *(requires Metal 2.0)*
- `VK_EXTX_portability_subset` - `VK_EXTX_portability_subset`
- `VK_MVK_ios_surface` *(iOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)* - `VK_MVK_ios_surface` *(iOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)*
- `VK_MVK_macos_surface` *(macOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)* - `VK_MVK_macos_surface` *(macOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)*

View File

@ -1 +1 @@
097a1045098213919fd56442f52c716fc78eeb27 737f4c1cd96283747967c2024a0108b742214455

View File

@ -336,6 +336,7 @@ protected:
VkPhysicalDeviceFeatures _features; VkPhysicalDeviceFeatures _features;
MVKPhysicalDeviceMetalFeatures _metalFeatures; MVKPhysicalDeviceMetalFeatures _metalFeatures;
VkPhysicalDeviceProperties _properties; VkPhysicalDeviceProperties _properties;
VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT _texelBuffAlignProperties;
VkPhysicalDeviceMemoryProperties _memoryProperties; VkPhysicalDeviceMemoryProperties _memoryProperties;
std::vector<MVKQueueFamily*> _queueFamilies; std::vector<MVKQueueFamily*> _queueFamilies;
uint32_t _allMemoryTypes; uint32_t _allMemoryTypes;

View File

@ -69,8 +69,7 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
if (features) { if (features) {
features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
features->features = _features; features->features = _features;
auto* next = (VkBaseOutStructure*)features->pNext; for (auto* next = (VkBaseOutStructure*)features->pNext; next; next = next->pNext) {
while (next) {
switch ((uint32_t)next->sType) { switch ((uint32_t)next->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {
auto* storageFeatures = (VkPhysicalDevice16BitStorageFeatures*)next; auto* storageFeatures = (VkPhysicalDevice16BitStorageFeatures*)next;
@ -109,6 +108,11 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
hostQueryResetFeatures->hostQueryReset = true; hostQueryResetFeatures->hostQueryReset = true;
break; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: {
auto* texelBuffAlignFeatures = (VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT*)next;
texelBuffAlignFeatures->texelBufferAlignment = _metalFeatures.texelBuffers && [_mtlDevice respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)];
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
auto* divisorFeatures = (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT*)next; auto* divisorFeatures = (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT*)next;
divisorFeatures->vertexAttributeInstanceRateDivisor = true; divisorFeatures->vertexAttributeInstanceRateDivisor = true;
@ -127,7 +131,6 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
default: default:
break; break;
} }
next = next->pNext;
} }
} }
} }
@ -140,42 +143,44 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
if (properties) { if (properties) {
properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties->properties = _properties; properties->properties = _properties;
auto* next = (MVKVkAPIStructHeader*)properties->pNext; for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
while (next) {
switch ((uint32_t)next->sType) { switch ((uint32_t)next->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next; auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES; pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
next = (MVKVkAPIStructHeader*)pointClipProps->pNext;
break; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
auto* maint3Props = (VkPhysicalDeviceMaintenance3Properties*)next; auto* maint3Props = (VkPhysicalDeviceMaintenance3Properties*)next;
maint3Props->maxPerSetDescriptors = (_metalFeatures.maxPerStageBufferCount + _metalFeatures.maxPerStageTextureCount + _metalFeatures.maxPerStageSamplerCount) * 2; maint3Props->maxPerSetDescriptors = (_metalFeatures.maxPerStageBufferCount + _metalFeatures.maxPerStageTextureCount + _metalFeatures.maxPerStageSamplerCount) * 4;
maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize; maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize;
next = (MVKVkAPIStructHeader*)maint3Props->pNext;
break; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next; auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources; pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
next = (MVKVkAPIStructHeader*)pushDescProps->pNext; break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
// Save the 'next' pointer; we'll unintentionally overwrite it
// on the next line. Put it back when we're done.
void* savedNext = texelBuffAlignProps->pNext;
*texelBuffAlignProps = _texelBuffAlignProperties;
texelBuffAlignProps->pNext = savedNext;
break; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next; auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32; divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
next = (MVKVkAPIStructHeader*)divisorProps->pNext;
break; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next; auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
portabilityProps->minVertexInputBindingStrideAlignment = 4; portabilityProps->minVertexInputBindingStrideAlignment = 4;
next = (MVKVkAPIStructHeader*)portabilityProps->pNext;
break; break;
} }
default: default:
next = (MVKVkAPIStructHeader*)next->pNext;
break; break;
} }
} }
@ -1113,14 +1118,86 @@ void MVKPhysicalDevice::initProperties() {
_properties.limits.bufferImageGranularity = _metalFeatures.mtlBufferAlignment; _properties.limits.bufferImageGranularity = _metalFeatures.mtlBufferAlignment;
_properties.limits.nonCoherentAtomSize = _metalFeatures.mtlBufferAlignment; _properties.limits.nonCoherentAtomSize = _metalFeatures.mtlBufferAlignment;
if ([_mtlDevice respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)]) {
// Figure out the greatest alignment required by all supported formats, and
// whether or not they only require alignment to a single texel. We'll use this
// information to fill out the VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT
// struct.
uint32_t maxStorage = 0, maxUniform = 0;
bool singleTexelStorage = true, singleTexelUniform = true;
mvkEnumerateSupportedFormats({0, 0, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT}, true, [&](VkFormat vk) {
NSUInteger alignment;
if ([_mtlDevice respondsToSelector: @selector(minimumTextureBufferAlignmentForPixelFormat:)]) {
alignment = [_mtlDevice minimumTextureBufferAlignmentForPixelFormat: mvkMTLPixelFormatFromVkFormat(vk)];
} else {
alignment = [_mtlDevice minimumLinearTextureAlignmentForPixelFormat: mvkMTLPixelFormatFromVkFormat(vk)];
}
VkFormatProperties props = mvkVkFormatProperties(vk, getFormatIsSupported(vk));
// For uncompressed formats, this is the size of a single texel.
// Note that no implementations of Metal support compressed formats
// in a linear texture (including texture buffers). It's likely that even
// if they did, this would be the absolute minimum alignment.
uint32_t texelSize = mvkVkFormatBytesPerBlock(vk);
// From the spec:
// "If the size of a single texel is a multiple of three bytes, then
// the size of a single component of the format is used instead."
if (texelSize % 3 == 0) {
switch (mvkFormatTypeFromVkFormat(vk)) {
case kMVKFormatColorInt8:
case kMVKFormatColorUInt8:
texelSize = 1;
break;
case kMVKFormatColorHalf:
case kMVKFormatColorInt16:
case kMVKFormatColorUInt16:
texelSize = 2;
break;
case kMVKFormatColorFloat:
case kMVKFormatColorInt32:
case kMVKFormatColorUInt32:
default:
texelSize = 4;
break;
}
}
if (mvkAreAllFlagsEnabled(props.bufferFeatures, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
maxStorage = max(maxStorage, uint32_t(alignment));
if (alignment % texelSize != 0) { singleTexelStorage = false; }
}
if (mvkAreAllFlagsEnabled(props.bufferFeatures, VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
maxUniform = max(maxUniform, uint32_t(alignment));
if (alignment % texelSize != 0) { singleTexelUniform = false; }
}
return true;
});
_texelBuffAlignProperties.storageTexelBufferOffsetAlignmentBytes = maxStorage;
_texelBuffAlignProperties.storageTexelBufferOffsetSingleTexelAlignment = singleTexelStorage;
_texelBuffAlignProperties.uniformTexelBufferOffsetAlignmentBytes = maxUniform;
_texelBuffAlignProperties.uniformTexelBufferOffsetSingleTexelAlignment = singleTexelUniform;
_properties.limits.minTexelBufferOffsetAlignment = max(maxStorage, maxUniform);
} else {
#if MVK_IOS
if ([_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1]) {
_properties.limits.minTexelBufferOffsetAlignment = 16;
} else {
_properties.limits.minTexelBufferOffsetAlignment = 64;
}
#endif
#if MVK_MACOS
_properties.limits.minTexelBufferOffsetAlignment = 256;
#endif
_texelBuffAlignProperties.storageTexelBufferOffsetAlignmentBytes = _properties.limits.minTexelBufferOffsetAlignment;
_texelBuffAlignProperties.storageTexelBufferOffsetSingleTexelAlignment = VK_FALSE;
_texelBuffAlignProperties.uniformTexelBufferOffsetAlignmentBytes = _properties.limits.minTexelBufferOffsetAlignment;
_texelBuffAlignProperties.uniformTexelBufferOffsetSingleTexelAlignment = VK_FALSE;
}
#if MVK_IOS #if MVK_IOS
_properties.limits.maxFragmentInputComponents = 60; _properties.limits.maxFragmentInputComponents = 60;
if ([_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1]) { if ([_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1]) {
_properties.limits.minTexelBufferOffsetAlignment = 16;
_properties.limits.optimalBufferCopyOffsetAlignment = 16; _properties.limits.optimalBufferCopyOffsetAlignment = 16;
} else { } else {
_properties.limits.minTexelBufferOffsetAlignment = 64;
_properties.limits.optimalBufferCopyOffsetAlignment = 64; _properties.limits.optimalBufferCopyOffsetAlignment = 64;
} }
@ -1137,7 +1214,6 @@ void MVKPhysicalDevice::initProperties() {
#endif #endif
#if MVK_MACOS #if MVK_MACOS
_properties.limits.maxFragmentInputComponents = 128; _properties.limits.maxFragmentInputComponents = 128;
_properties.limits.minTexelBufferOffsetAlignment = 256;
_properties.limits.optimalBufferCopyOffsetAlignment = 256; _properties.limits.optimalBufferCopyOffsetAlignment = 256;
if ([_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily1_v2]) { if ([_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily1_v2]) {

View File

@ -62,6 +62,7 @@ MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE)
MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT) MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT)
MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER) MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER)
MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE) MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE)
MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT)
MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR) MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR)
MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET) MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET)
MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE) MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE)

View File

@ -53,6 +53,9 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) { if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
return mvkOSVersion() >= 10.14; return mvkOSVersion() >= 10.14;
} }
if (pProperties == &kVkExtProps_EXT_TEXEL_BUFFER_ALIGNMENT) {
return mvkOSVersion() >= 10.13;
}
if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; } if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; }
if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; } if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; }
#endif #endif
@ -65,6 +68,9 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
return mvkOSVersion() >= 12.0; return mvkOSVersion() >= 12.0;
} }
if (pProperties == &kVkExtProps_EXT_SWAPCHAIN_COLOR_SPACE) { return false; } if (pProperties == &kVkExtProps_EXT_SWAPCHAIN_COLOR_SPACE) { return false; }
if (pProperties == &kVkExtProps_EXT_TEXEL_BUFFER_ALIGNMENT) {
return mvkOSVersion() >= 11.0;
}
if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; } if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; }
#endif #endif

View File

@ -22,6 +22,8 @@
#include "mvk_datatypes.h" #include "mvk_datatypes.h"
#include <functional>
class MVKBaseObject; class MVKBaseObject;
/* /*
@ -75,4 +77,13 @@ MTLWinding mvkMTLWindingFromSpvExecutionModeInObj(uint32_t spvMode, MVKBaseObjec
MTLTessellationPartitionMode mvkMTLTessellationPartitionModeFromSpvExecutionModeInObj(uint32_t spvMode, MVKBaseObject* mvkObj); MTLTessellationPartitionMode mvkMTLTessellationPartitionModeFromSpvExecutionModeInObj(uint32_t spvMode, MVKBaseObject* mvkObj);
#define mvkMTLTessellationPartitionModeFromSpvExecutionMode(spvMode) mvkMTLTessellationPartitionModeFromSpvExecutionModeInObj(spvMode, this) #define mvkMTLTessellationPartitionModeFromSpvExecutionMode(spvMode) mvkMTLTessellationPartitionModeFromSpvExecutionModeInObj(spvMode, this)
#pragma mark -
#pragma mark Image properties
#pragma mark Texture formats
/** Enumerates all formats that support the given features, calling a specified function for each one. */
void mvkEnumerateSupportedFormats(VkFormatProperties properties, bool any, std::function<bool(VkFormat)> func);
#endif #endif

View File

@ -665,6 +665,25 @@ MVK_PUBLIC_SYMBOL const char* mvkMTLPixelFormatName(MTLPixelFormat mtlFormat) {
return formatDescForMTLPixelFormat(mtlFormat).mtlName; return formatDescForMTLPixelFormat(mtlFormat).mtlName;
} }
void mvkEnumerateSupportedFormats(VkFormatProperties properties, bool any, std::function<bool(VkFormat)> func) {
static const auto areFeaturesSupported = [any](uint32_t a, uint32_t b) {
if (any)
return mvkIsAnyFlagEnabled(a, b);
else
return mvkAreAllFlagsEnabled(a, b);
};
for (auto& formatDesc : _formatDescriptions) {
if (formatDesc.isSupported() &&
areFeaturesSupported(formatDesc.properties.linearTilingFeatures, properties.linearTilingFeatures) &&
areFeaturesSupported(formatDesc.properties.optimalTilingFeatures, properties.optimalTilingFeatures) &&
areFeaturesSupported(formatDesc.properties.bufferFeatures, properties.bufferFeatures)) {
if (!func(formatDesc.vk)) {
break;
}
}
}
}
#undef mvkMTLVertexFormatFromVkFormat #undef mvkMTLVertexFormatFromVkFormat
MVK_PUBLIC_SYMBOL MTLVertexFormat mvkMTLVertexFormatFromVkFormat(VkFormat vkFormat) { MVK_PUBLIC_SYMBOL MTLVertexFormat mvkMTLVertexFormatFromVkFormat(VkFormat vkFormat) {
return mvkMTLVertexFormatFromVkFormatInObj(vkFormat, nullptr); return mvkMTLVertexFormatFromVkFormatInObj(vkFormat, nullptr);