From fc13aec2af8fd0bbbb2ec38298c7823c8102ee34 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sat, 29 Jun 2019 19:16:16 -0500 Subject: [PATCH] Advertise the VK_EXT_shader_stencil_export extension. This is supported by Mac GPU Family 2 starting on macOS 10.14, and Apple GPU Family 5 starting on iOS 12. Supporting this is a bit tricky. Because only some devices support this extension, we now have to keep track of supported device extensions per device. --- Docs/MoltenVK_Runtime_UserGuide.md | 3 +- MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 1 + MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 6 ++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 24 +++++++++++++-- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Layers/MVKExtensions.h | 14 +++++++++ MoltenVK/MoltenVK/Layers/MVKExtensions.mm | 34 ++++++++++++++++++++++ MoltenVK/MoltenVK/Layers/MVKLayers.mm | 24 +-------------- MoltenVK/MoltenVK/Vulkan/vulkan.mm | 2 +- 9 files changed, 82 insertions(+), 27 deletions(-) diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 1b36bfb1..a0d5107c 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -240,7 +240,7 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following - `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` @@ -254,6 +254,7 @@ In addition to the core *Vulkan* API, **MoltenVK** also supports the following - `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 cf0f232b..7365f17b 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -537,6 +537,7 @@ typedef struct { 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. */ } MVKPhysicalDeviceMetalFeatures; /** diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index e1700754..233d360b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -88,6 +88,9 @@ public: /** 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 @@ protected: void initFeatures(); void initProperties(); void initMemoryProperties(); + void initExtensions(); + MVKExtensionList* getSupportedExtensions(const char* pLayerName = nullptr); std::vector& getQueueFamilies(); void initPipelineCacheUUID(); MTLFeatureSet getHighestMTLFeatureSet(); @@ -327,6 +332,7 @@ protected: id _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 e697ab8e..30c2a4a4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -56,6 +56,11 @@ using namespace std; #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; } } @@ -676,7 +681,7 @@ VkResult MVKPhysicalDevice::getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMe #pragma mark Construction -MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id mtlDevice) { +MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id mtlDevice) : _supportedExtensions(this, true) { _mvkInstance = mvkInstance; _mtlDevice = [mtlDevice retain]; @@ -684,6 +689,7 @@ MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id mtl initFeatures(); // Call second. initProperties(); // Call third. initMemoryProperties(); + initExtensions(); logGPUInfo(); } @@ -751,6 +757,7 @@ void MVKPhysicalDevice::initMetalFeatures() { if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily5_v1] ) { _metalFeatures.layeredRendering = true; + _metalFeatures.stencilFeedback = true; } #endif @@ -793,6 +800,7 @@ void MVKPhysicalDevice::initMetalFeatures() { if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1] ) { _metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering; + _metalFeatures.stencilFeedback = true; } #endif @@ -1499,6 +1507,18 @@ void MVKPhysicalDevice::initMemoryProperties() { #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 +2300,7 @@ void MVKDevice::enableExtensions(const VkDeviceCreateInfo* pCreateInfo) { 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/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index c066bd6d..2d9e0e1f 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -58,6 +58,7 @@ MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS) 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 e93fa501..f42aa0fd 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.h +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.h @@ -85,6 +85,20 @@ public: */ 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 8ca031af..e1580dc2 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm @@ -50,6 +50,9 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { 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 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { 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 @@ string MVKExtensionList::enabledNamesString(const char* separator, bool prefixFi } 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 bbc5a79b..0fb19e60 100644 --- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm +++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm @@ -32,29 +32,7 @@ VkLayerProperties* const MVKLayer::getLayerProperties() { return &_layerProperti 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 f4875b24..8a287a55 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -282,7 +282,7 @@ MVK_PUBLIC_SYMBOL VkResult vkEnumerateDeviceExtensionProperties( 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; }