Merge branch 'master' of https://github.com/KhronosGroup/MoltenVK
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 1b36bfb..a89e672 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -240,13 +240,14 @@
- `VK_KHR_maintenance3`
- `VK_KHR_push_descriptor`
- `VK_KHR_relaxed_block_layout`
-- `VK_KHR_sampler_mirror_clamp_to_edge`
+- `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
- `VK_KHR_shader_draw_parameters`
- `VK_KHR_shader_float16_int8`
- `VK_KHR_storage_buffer_storage_class`
- `VK_KHR_surface`
- `VK_KHR_swapchain`
- `VK_KHR_swapchain_mutable_format`
+- `VK_KHR_uniform_buffer_standard_layout`
- `VK_KHR_variable_pointers`
- `VK_EXT_debug_marker`
- `VK_EXT_debug_report`
@@ -254,6 +255,7 @@
- `VK_EXT_host_query_reset`
- `VK_EXT_memory_budget`
- `VK_EXT_metal_surface`
+- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
- `VK_EXT_shader_viewport_index_layer`
- `VK_EXT_vertex_attribute_divisor`
- `VK_EXTX_portability_subset`
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index cf0f232..27bac91 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -537,6 +537,8 @@
VkBool32 events; /**< If true, Metal synchronization events are supported. */
VkBool32 memoryBarriers; /**< If true, full memory barriers within Metal render passes are supported. */
VkBool32 multisampleLayeredRendering; /**< If true, layered rendering to multiple multi-sampled cube or texture array layers is supported. */
+ VkBool32 stencilFeedback; /**< If true, fragment shaders that write to [[stencil]] outputs are supported. */
+ VkBool32 textureBuffers; /**< If true, textures of type MTLTextureTypeBuffer are supported. */
} MVKPhysicalDeviceMetalFeatures;
/**
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
index f56cd86..e60dab4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
@@ -162,16 +162,25 @@
lock_guard<mutex> lock(_lock);
if (_mtlTexture) { return _mtlTexture; }
- MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: _mtlPixelFormat
- width: _textureSize.width
- height: _textureSize.height
- mipmapped: NO];
- id<MTLBuffer> mtlBuff = _buffer->getMTLBuffer();
- mtlTexDesc.storageMode = mtlBuff.storageMode;
- mtlTexDesc.cpuCacheMode = mtlBuff.cpuCacheMode;
- mtlTexDesc.usage = MTLTextureUsageShaderRead;
+ MTLTextureUsage usage = MTLTextureUsageShaderRead;
if ( mvkIsAnyFlagEnabled(_buffer->getUsage(), VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) ) {
- mtlTexDesc.usage |= MTLTextureUsageShaderWrite;
+ usage |= MTLTextureUsageShaderWrite;
+ }
+ id<MTLBuffer> mtlBuff = _buffer->getMTLBuffer();
+ MTLTextureDescriptor* mtlTexDesc;
+ if ( _device->_pMetalFeatures->textureBuffers ) {
+ mtlTexDesc = [MTLTextureDescriptor textureBufferDescriptorWithPixelFormat: _mtlPixelFormat
+ width: _textureSize.width
+ resourceOptions: (mtlBuff.cpuCacheMode << MTLResourceCPUCacheModeShift) | (mtlBuff.storageMode << MTLResourceStorageModeShift)
+ usage: usage];
+ } else {
+ mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: _mtlPixelFormat
+ width: _textureSize.width
+ height: _textureSize.height
+ mipmapped: NO];
+ mtlTexDesc.storageMode = mtlBuff.storageMode;
+ mtlTexDesc.cpuCacheMode = mtlBuff.cpuCacheMode;
+ mtlTexDesc.usage = usage;
}
_mtlTexture = [_buffer->getMTLBuffer() newTextureWithDescriptor: mtlTexDesc
offset: _mtlBufferOffset
@@ -197,17 +206,24 @@
if (byteCount == VK_WHOLE_SIZE) { byteCount = _buffer->getByteCount() - pCreateInfo->offset; } // Remaining bytes in buffer
size_t blockCount = byteCount / bytesPerBlock;
- // But Metal requires the texture to be a 2D texture. Determine the number of 2D rows we need and their width.
- // Multiple rows will automatically align with PoT max texture dimension, but need to align upwards if less than full single row.
- size_t maxBlocksPerRow = _device->_pMetalFeatures->maxTextureDimension / fmtBlockSize.width;
- size_t blocksPerRow = min(blockCount, maxBlocksPerRow);
- _mtlBytesPerRow = mvkAlignByteOffset(blocksPerRow * bytesPerBlock, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format, this));
+ if ( !_device->_pMetalFeatures->textureBuffers ) {
+ // But Metal requires the texture to be a 2D texture. Determine the number of 2D rows we need and their width.
+ // Multiple rows will automatically align with PoT max texture dimension, but need to align upwards if less than full single row.
+ size_t maxBlocksPerRow = _device->_pMetalFeatures->maxTextureDimension / fmtBlockSize.width;
+ size_t blocksPerRow = min(blockCount, maxBlocksPerRow);
+ _mtlBytesPerRow = mvkAlignByteOffset(blocksPerRow * bytesPerBlock, _device->getVkFormatTexelBufferAlignment(pCreateInfo->format, this));
- size_t rowCount = blockCount / blocksPerRow;
- if (blockCount % blocksPerRow) { rowCount++; }
+ size_t rowCount = blockCount / blocksPerRow;
+ if (blockCount % blocksPerRow) { rowCount++; }
- _textureSize.width = uint32_t(blocksPerRow * fmtBlockSize.width);
- _textureSize.height = uint32_t(rowCount * fmtBlockSize.height);
+ _textureSize.width = uint32_t(blocksPerRow * fmtBlockSize.width);
+ _textureSize.height = uint32_t(rowCount * fmtBlockSize.height);
+ } else {
+ // With native texture buffers we don't need to bother with any of that.
+ // We can just use a simple 1D texel array.
+ _textureSize.width = uint32_t(blockCount * fmtBlockSize.width);
+ _textureSize.height = 1;
+ }
if ( !_device->_pMetalFeatures->texelBuffers ) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Texel buffers are not supported on this device."));
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index e170075..233d360 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -88,6 +88,9 @@
/** Returns a pointer to the Vulkan instance. */
MVKInstance* getInstance() override { return _mvkInstance; }
+ /** Populates the specified array with the supported extensions of this device. */
+ VkResult getExtensionProperties(const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties);
+
/** Populates the specified structure with the features of this device. */
void getFeatures(VkPhysicalDeviceFeatures* features);
@@ -318,6 +321,8 @@
void initFeatures();
void initProperties();
void initMemoryProperties();
+ void initExtensions();
+ MVKExtensionList* getSupportedExtensions(const char* pLayerName = nullptr);
std::vector<MVKQueueFamily*>& getQueueFamilies();
void initPipelineCacheUUID();
MTLFeatureSet getHighestMTLFeatureSet();
@@ -327,6 +332,7 @@
id<MTLDevice> _mtlDevice;
MVKInstance* _mvkInstance;
+ MVKExtensionList _supportedExtensions;
VkPhysicalDeviceFeatures _features;
MVKPhysicalDeviceMetalFeatures _metalFeatures;
VkPhysicalDeviceProperties _properties;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index e697ab8..9bc202d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -56,6 +56,11 @@
#pragma mark -
#pragma mark MVKPhysicalDevice
+VkResult MVKPhysicalDevice::getExtensionProperties(const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties) {
+ MVKExtensionList* extensions = getSupportedExtensions(pLayerName);
+ return extensions->getProperties(pCount, pProperties);
+}
+
void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures* features) {
if (features) { *features = _features; }
}
@@ -88,6 +93,11 @@
f16Features->shaderInt8 = true;
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
+ auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next;
+ uboLayoutFeatures->uniformBufferStandardLayout = true;
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES: {
auto* varPtrFeatures = (VkPhysicalDeviceVariablePointerFeatures*)next;
varPtrFeatures->variablePointersStorageBuffer = true;
@@ -676,7 +686,7 @@
#pragma mark Construction
-MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) {
+MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) : _supportedExtensions(this, true) {
_mvkInstance = mvkInstance;
_mtlDevice = [mtlDevice retain];
@@ -684,6 +694,7 @@
initFeatures(); // Call second.
initProperties(); // Call third.
initMemoryProperties();
+ initExtensions();
logGPUInfo();
}
@@ -731,6 +742,7 @@
if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v5] ) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_1;
MVK_SET_FROM_ENV_OR_BUILD_BOOL(_metalFeatures.events, MVK_ALLOW_METAL_EVENTS);
+ _metalFeatures.textureBuffers = true;
}
if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily3_v1] ) {
@@ -751,6 +763,7 @@
if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily5_v1] ) {
_metalFeatures.layeredRendering = true;
+ _metalFeatures.stencilFeedback = true;
}
#endif
@@ -789,10 +802,12 @@
_metalFeatures.multisampleArrayTextures = true;
MVK_SET_FROM_ENV_OR_BUILD_BOOL(_metalFeatures.events, MVK_ALLOW_METAL_EVENTS);
_metalFeatures.memoryBarriers = true;
+ _metalFeatures.textureBuffers = true;
}
if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1] ) {
_metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering;
+ _metalFeatures.stencilFeedback = true;
}
#endif
@@ -1499,6 +1514,18 @@
#endif
}
+void MVKPhysicalDevice::initExtensions() {
+ if (!_metalFeatures.stencilFeedback) {
+ _supportedExtensions.vk_EXT_shader_stencil_export.enabled = false;
+ }
+}
+
+// Return all extensions supported by this physical device.
+MVKExtensionList* MVKPhysicalDevice::getSupportedExtensions(const char* pLayerName) {
+ if (!pLayerName || strcmp(pLayerName, "MoltenVK") == 0) { return &_supportedExtensions; }
+ return getInstance()->getLayerManager()->getLayerNamed(pLayerName)->getSupportedExtensions();
+}
+
void MVKPhysicalDevice::logGPUInfo() {
string devTypeStr;
switch (_properties.deviceType) {
@@ -2280,7 +2307,7 @@
MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions;
setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount,
pCreateInfo->ppEnabledExtensionNames,
- getInstance()->getDriverLayer()->getSupportedExtensions()));
+ getPhysicalDevice()->getSupportedExtensions()));
}
// Create the command queues
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index abbdc49..84fa930 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -1129,6 +1129,7 @@
shaderContext.options.mslOptions.msl_version = _device->_pMetalFeatures->mslVersion;
shaderContext.options.mslOptions.texel_buffer_texture_width = _device->_pMetalFeatures->maxTextureDimension;
+ shaderContext.options.mslOptions.texture_buffer_native = _device->_pMetalFeatures->textureBuffers;
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
@@ -1321,6 +1322,7 @@
shaderContext.options.mslOptions.msl_version = _device->_pMetalFeatures->mslVersion;
shaderContext.options.mslOptions.texel_buffer_texture_width = _device->_pMetalFeatures->maxTextureDimension;
shaderContext.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle;
+ shaderContext.options.mslOptions.texture_buffer_native = _device->_pMetalFeatures->textureBuffers;
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index c066bd6..5235f43 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -51,6 +51,7 @@
MVK_EXTENSION(KHR_surface, KHR_SURFACE)
MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN)
MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT)
+MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT)
MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS)
MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER)
MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT)
@@ -58,6 +59,7 @@
MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET)
MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET)
MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE)
+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_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR)
MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET)
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.h b/MoltenVK/MoltenVK/Layers/MVKExtensions.h
index e93fa50..f42aa0f 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.h
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.h
@@ -85,6 +85,20 @@
*/
std::string enabledNamesString(const char* separator = " ", bool prefixFirstWithSeparator = false) const;
+ /**
+ * If pProperties is null, the value of pCount is updated with the number of extensions
+ * enabled in this list.
+ *
+ * If pProperties is not null, then pCount extension properties are copied into the array.
+ * If the number of available extensions is less than pCount, the value of pCount is updated
+ * to indicate the number of extension properties actually returned in the array.
+ *
+ * Returns VK_SUCCESS if successful. Returns VK_INCOMPLETE if the number of extensions
+ * enabled in this list is larger than the specified pCount. Returns other values
+ * if an error occurs.
+ */
+ VkResult getProperties(uint32_t* pCount, VkExtensionProperties* pProperties);
+
MVKExtensionList(MVKVulkanAPIObject* apiObject, bool enableForPlatform = false);
protected:
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
index 8ca031a..e1580dc 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
@@ -50,6 +50,9 @@
if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
return mvkOSVersion() >= 10.13;
}
+ if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
+ return mvkOSVersion() >= 10.14;
+ }
if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; }
if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; }
#endif
@@ -58,6 +61,9 @@
if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
return mvkOSVersion() >= 11.0;
}
+ if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
+ return mvkOSVersion() >= 12.0;
+ }
if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; }
#endif
@@ -157,3 +163,31 @@
}
return logMsg;
}
+
+VkResult MVKExtensionList::getProperties(uint32_t* pCount, VkExtensionProperties* pProperties) {
+
+ uint32_t enabledCnt = 0;
+
+ // Iterate extensions and handle those that are enabled. Count them,
+ // and if they are to be returned, and there is room, do so.
+ uint32_t extnCnt = getCount();
+ MVKExtension* extnAry = &extensionArray;
+ for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
+ if (extnAry[extnIdx].enabled) {
+ if (pProperties) {
+ if (enabledCnt < *pCount) {
+ pProperties[enabledCnt] = *(extnAry[extnIdx].pProperties);
+ } else {
+ return VK_INCOMPLETE;
+ }
+ }
+ enabledCnt++;
+ }
+ }
+
+ // Return the count of enabled extensions. This will either be a
+ // count of all enabled extensions, or a count of those returned.
+ *pCount = enabledCnt;
+ return VK_SUCCESS;
+}
+
diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
index bbc5a79..0fb19e6 100644
--- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
@@ -32,29 +32,7 @@
VkResult MVKLayer::getExtensionProperties(uint32_t* pCount, VkExtensionProperties* pProperties) {
- uint32_t enabledCnt = 0;
-
- // Iterate extensions and handle those that are enabled. Count them,
- // and if they are to be returned, and there is room, do so.
- uint32_t extnCnt = _supportedExtensions.getCount();
- MVKExtension* extnAry = &_supportedExtensions.extensionArray;
- for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
- if (extnAry[extnIdx].enabled) {
- if (pProperties) {
- if (enabledCnt < *pCount) {
- pProperties[enabledCnt] = *(extnAry[extnIdx].pProperties);
- } else {
- return VK_INCOMPLETE;
- }
- }
- enabledCnt++;
- }
- }
-
- // Return the count of enabled extensions. This will either be a
- // count of all enabled extensions, or a count of those returned.
- *pCount = enabledCnt;
- return VK_SUCCESS;
+ return _supportedExtensions.getProperties(pCount, pProperties);
}
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index f4875b2..8a287a5 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -282,7 +282,7 @@
MVKTraceVulkanCallStart();
MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- VkResult rslt = mvkPD->getInstance()->getLayerManager()->getLayerNamed(pLayerName)->getExtensionProperties(pCount, pProperties);
+ VkResult rslt = mvkPD->getExtensionProperties(pLayerName, pCount, pProperties);
MVKTraceVulkanCallEnd();
return rslt;
}